github.com/andybalholm/brotli@v1.0.6/compress_fragment.go (about)

     1  package brotli
     2  
     3  import "encoding/binary"
     4  
     5  /* Copyright 2015 Google Inc. All Rights Reserved.
     6  
     7     Distributed under MIT license.
     8     See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
     9  */
    10  
    11  /* Function for fast encoding of an input fragment, independently from the input
    12     history. This function uses one-pass processing: when we find a backward
    13     match, we immediately emit the corresponding command and literal codes to
    14     the bit stream.
    15  
    16     Adapted from the CompressFragment() function in
    17     https://github.com/google/snappy/blob/master/snappy.cc */
    18  
    19  const maxDistance_compress_fragment = 262128
    20  
    21  func hash5(p []byte, shift uint) uint32 {
    22  	var h uint64 = (binary.LittleEndian.Uint64(p) << 24) * uint64(kHashMul32)
    23  	return uint32(h >> shift)
    24  }
    25  
    26  func hashBytesAtOffset5(v uint64, offset int, shift uint) uint32 {
    27  	assert(offset >= 0)
    28  	assert(offset <= 3)
    29  	{
    30  		var h uint64 = ((v >> uint(8*offset)) << 24) * uint64(kHashMul32)
    31  		return uint32(h >> shift)
    32  	}
    33  }
    34  
    35  func isMatch5(p1 []byte, p2 []byte) bool {
    36  	return binary.LittleEndian.Uint32(p1) == binary.LittleEndian.Uint32(p2) &&
    37  		p1[4] == p2[4]
    38  }
    39  
    40  /* Builds a literal prefix code into "depths" and "bits" based on the statistics
    41     of the "input" string and stores it into the bit stream.
    42     Note that the prefix code here is built from the pre-LZ77 input, therefore
    43     we can only approximate the statistics of the actual literal stream.
    44     Moreover, for long inputs we build a histogram from a sample of the input
    45     and thus have to assign a non-zero depth for each literal.
    46     Returns estimated compression ratio millibytes/char for encoding given input
    47     with generated code. */
    48  func buildAndStoreLiteralPrefixCode(input []byte, input_size uint, depths []byte, bits []uint16, storage_ix *uint, storage []byte) uint {
    49  	var histogram = [256]uint32{0}
    50  	var histogram_total uint
    51  	var i uint
    52  	if input_size < 1<<15 {
    53  		for i = 0; i < input_size; i++ {
    54  			histogram[input[i]]++
    55  		}
    56  
    57  		histogram_total = input_size
    58  		for i = 0; i < 256; i++ {
    59  			/* We weigh the first 11 samples with weight 3 to account for the
    60  			   balancing effect of the LZ77 phase on the histogram. */
    61  			var adjust uint32 = 2 * brotli_min_uint32_t(histogram[i], 11)
    62  			histogram[i] += adjust
    63  			histogram_total += uint(adjust)
    64  		}
    65  	} else {
    66  		const kSampleRate uint = 29
    67  		for i = 0; i < input_size; i += kSampleRate {
    68  			histogram[input[i]]++
    69  		}
    70  
    71  		histogram_total = (input_size + kSampleRate - 1) / kSampleRate
    72  		for i = 0; i < 256; i++ {
    73  			/* We add 1 to each population count to avoid 0 bit depths (since this is
    74  			   only a sample and we don't know if the symbol appears or not), and we
    75  			   weigh the first 11 samples with weight 3 to account for the balancing
    76  			   effect of the LZ77 phase on the histogram (more frequent symbols are
    77  			   more likely to be in backward references instead as literals). */
    78  			var adjust uint32 = 1 + 2*brotli_min_uint32_t(histogram[i], 11)
    79  			histogram[i] += adjust
    80  			histogram_total += uint(adjust)
    81  		}
    82  	}
    83  
    84  	buildAndStoreHuffmanTreeFast(histogram[:], histogram_total, /* max_bits = */
    85  		8, depths, bits, storage_ix, storage)
    86  	{
    87  		var literal_ratio uint = 0
    88  		for i = 0; i < 256; i++ {
    89  			if histogram[i] != 0 {
    90  				literal_ratio += uint(histogram[i] * uint32(depths[i]))
    91  			}
    92  		}
    93  
    94  		/* Estimated encoding ratio, millibytes per symbol. */
    95  		return (literal_ratio * 125) / histogram_total
    96  	}
    97  }
    98  
    99  /* Builds a command and distance prefix code (each 64 symbols) into "depth" and
   100     "bits" based on "histogram" and stores it into the bit stream. */
   101  func buildAndStoreCommandPrefixCode1(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
   102  	var tree [129]huffmanTree
   103  	var cmd_depth = [numCommandSymbols]byte{0}
   104  	/* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
   105  
   106  	var cmd_bits [64]uint16
   107  
   108  	createHuffmanTree(histogram, 64, 15, tree[:], depth)
   109  	createHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:])
   110  
   111  	/* We have to jump through a few hoops here in order to compute
   112  	   the command bits because the symbols are in a different order than in
   113  	   the full alphabet. This looks complicated, but having the symbols
   114  	   in this order in the command bits saves a few branches in the Emit*
   115  	   functions. */
   116  	copy(cmd_depth[:], depth[:24])
   117  
   118  	copy(cmd_depth[24:][:], depth[40:][:8])
   119  	copy(cmd_depth[32:][:], depth[24:][:8])
   120  	copy(cmd_depth[40:][:], depth[48:][:8])
   121  	copy(cmd_depth[48:][:], depth[32:][:8])
   122  	copy(cmd_depth[56:][:], depth[56:][:8])
   123  	convertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:])
   124  	copy(bits, cmd_bits[:24])
   125  	copy(bits[24:], cmd_bits[32:][:8])
   126  	copy(bits[32:], cmd_bits[48:][:8])
   127  	copy(bits[40:], cmd_bits[24:][:8])
   128  	copy(bits[48:], cmd_bits[40:][:8])
   129  	copy(bits[56:], cmd_bits[56:][:8])
   130  	convertBitDepthsToSymbols(depth[64:], 64, bits[64:])
   131  	{
   132  		/* Create the bit length array for the full command alphabet. */
   133  		var i uint
   134  		for i := 0; i < int(64); i++ {
   135  			cmd_depth[i] = 0
   136  		} /* only 64 first values were used */
   137  		copy(cmd_depth[:], depth[:8])
   138  		copy(cmd_depth[64:][:], depth[8:][:8])
   139  		copy(cmd_depth[128:][:], depth[16:][:8])
   140  		copy(cmd_depth[192:][:], depth[24:][:8])
   141  		copy(cmd_depth[384:][:], depth[32:][:8])
   142  		for i = 0; i < 8; i++ {
   143  			cmd_depth[128+8*i] = depth[40+i]
   144  			cmd_depth[256+8*i] = depth[48+i]
   145  			cmd_depth[448+8*i] = depth[56+i]
   146  		}
   147  
   148  		storeHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage)
   149  	}
   150  
   151  	storeHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage)
   152  }
   153  
   154  /* REQUIRES: insertlen < 6210 */
   155  func emitInsertLen1(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {
   156  	if insertlen < 6 {
   157  		var code uint = insertlen + 40
   158  		writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
   159  		histo[code]++
   160  	} else if insertlen < 130 {
   161  		var tail uint = insertlen - 2
   162  		var nbits uint32 = log2FloorNonZero(tail) - 1
   163  		var prefix uint = tail >> nbits
   164  		var inscode uint = uint((nbits << 1) + uint32(prefix) + 42)
   165  		writeBits(uint(depth[inscode]), uint64(bits[inscode]), storage_ix, storage)
   166  		writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage)
   167  		histo[inscode]++
   168  	} else if insertlen < 2114 {
   169  		var tail uint = insertlen - 66
   170  		var nbits uint32 = log2FloorNonZero(tail)
   171  		var code uint = uint(nbits + 50)
   172  		writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
   173  		writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage)
   174  		histo[code]++
   175  	} else {
   176  		writeBits(uint(depth[61]), uint64(bits[61]), storage_ix, storage)
   177  		writeBits(12, uint64(insertlen)-2114, storage_ix, storage)
   178  		histo[61]++
   179  	}
   180  }
   181  
   182  func emitLongInsertLen(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {
   183  	if insertlen < 22594 {
   184  		writeBits(uint(depth[62]), uint64(bits[62]), storage_ix, storage)
   185  		writeBits(14, uint64(insertlen)-6210, storage_ix, storage)
   186  		histo[62]++
   187  	} else {
   188  		writeBits(uint(depth[63]), uint64(bits[63]), storage_ix, storage)
   189  		writeBits(24, uint64(insertlen)-22594, storage_ix, storage)
   190  		histo[63]++
   191  	}
   192  }
   193  
   194  func emitCopyLen1(copylen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {
   195  	if copylen < 10 {
   196  		writeBits(uint(depth[copylen+14]), uint64(bits[copylen+14]), storage_ix, storage)
   197  		histo[copylen+14]++
   198  	} else if copylen < 134 {
   199  		var tail uint = copylen - 6
   200  		var nbits uint32 = log2FloorNonZero(tail) - 1
   201  		var prefix uint = tail >> nbits
   202  		var code uint = uint((nbits << 1) + uint32(prefix) + 20)
   203  		writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
   204  		writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage)
   205  		histo[code]++
   206  	} else if copylen < 2118 {
   207  		var tail uint = copylen - 70
   208  		var nbits uint32 = log2FloorNonZero(tail)
   209  		var code uint = uint(nbits + 28)
   210  		writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
   211  		writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage)
   212  		histo[code]++
   213  	} else {
   214  		writeBits(uint(depth[39]), uint64(bits[39]), storage_ix, storage)
   215  		writeBits(24, uint64(copylen)-2118, storage_ix, storage)
   216  		histo[39]++
   217  	}
   218  }
   219  
   220  func emitCopyLenLastDistance1(copylen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {
   221  	if copylen < 12 {
   222  		writeBits(uint(depth[copylen-4]), uint64(bits[copylen-4]), storage_ix, storage)
   223  		histo[copylen-4]++
   224  	} else if copylen < 72 {
   225  		var tail uint = copylen - 8
   226  		var nbits uint32 = log2FloorNonZero(tail) - 1
   227  		var prefix uint = tail >> nbits
   228  		var code uint = uint((nbits << 1) + uint32(prefix) + 4)
   229  		writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
   230  		writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage)
   231  		histo[code]++
   232  	} else if copylen < 136 {
   233  		var tail uint = copylen - 8
   234  		var code uint = (tail >> 5) + 30
   235  		writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
   236  		writeBits(5, uint64(tail)&31, storage_ix, storage)
   237  		writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)
   238  		histo[code]++
   239  		histo[64]++
   240  	} else if copylen < 2120 {
   241  		var tail uint = copylen - 72
   242  		var nbits uint32 = log2FloorNonZero(tail)
   243  		var code uint = uint(nbits + 28)
   244  		writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
   245  		writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage)
   246  		writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)
   247  		histo[code]++
   248  		histo[64]++
   249  	} else {
   250  		writeBits(uint(depth[39]), uint64(bits[39]), storage_ix, storage)
   251  		writeBits(24, uint64(copylen)-2120, storage_ix, storage)
   252  		writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)
   253  		histo[39]++
   254  		histo[64]++
   255  	}
   256  }
   257  
   258  func emitDistance1(distance uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {
   259  	var d uint = distance + 3
   260  	var nbits uint32 = log2FloorNonZero(d) - 1
   261  	var prefix uint = (d >> nbits) & 1
   262  	var offset uint = (2 + prefix) << nbits
   263  	var distcode uint = uint(2*(nbits-1) + uint32(prefix) + 80)
   264  	writeBits(uint(depth[distcode]), uint64(bits[distcode]), storage_ix, storage)
   265  	writeBits(uint(nbits), uint64(d)-uint64(offset), storage_ix, storage)
   266  	histo[distcode]++
   267  }
   268  
   269  func emitLiterals(input []byte, len uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
   270  	var j uint
   271  	for j = 0; j < len; j++ {
   272  		var lit byte = input[j]
   273  		writeBits(uint(depth[lit]), uint64(bits[lit]), storage_ix, storage)
   274  	}
   275  }
   276  
   277  /* REQUIRES: len <= 1 << 24. */
   278  func storeMetaBlockHeader1(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) {
   279  	var nibbles uint = 6
   280  
   281  	/* ISLAST */
   282  	writeBits(1, 0, storage_ix, storage)
   283  
   284  	if len <= 1<<16 {
   285  		nibbles = 4
   286  	} else if len <= 1<<20 {
   287  		nibbles = 5
   288  	}
   289  
   290  	writeBits(2, uint64(nibbles)-4, storage_ix, storage)
   291  	writeBits(nibbles*4, uint64(len)-1, storage_ix, storage)
   292  
   293  	/* ISUNCOMPRESSED */
   294  	writeSingleBit(is_uncompressed, storage_ix, storage)
   295  }
   296  
   297  func updateBits(n_bits uint, bits uint32, pos uint, array []byte) {
   298  	for n_bits > 0 {
   299  		var byte_pos uint = pos >> 3
   300  		var n_unchanged_bits uint = pos & 7
   301  		var n_changed_bits uint = brotli_min_size_t(n_bits, 8-n_unchanged_bits)
   302  		var total_bits uint = n_unchanged_bits + n_changed_bits
   303  		var mask uint32 = (^((1 << total_bits) - 1)) | ((1 << n_unchanged_bits) - 1)
   304  		var unchanged_bits uint32 = uint32(array[byte_pos]) & mask
   305  		var changed_bits uint32 = bits & ((1 << n_changed_bits) - 1)
   306  		array[byte_pos] = byte(changed_bits<<n_unchanged_bits | unchanged_bits)
   307  		n_bits -= n_changed_bits
   308  		bits >>= n_changed_bits
   309  		pos += n_changed_bits
   310  	}
   311  }
   312  
   313  func rewindBitPosition1(new_storage_ix uint, storage_ix *uint, storage []byte) {
   314  	var bitpos uint = new_storage_ix & 7
   315  	var mask uint = (1 << bitpos) - 1
   316  	storage[new_storage_ix>>3] &= byte(mask)
   317  	*storage_ix = new_storage_ix
   318  }
   319  
   320  var shouldMergeBlock_kSampleRate uint = 43
   321  
   322  func shouldMergeBlock(data []byte, len uint, depths []byte) bool {
   323  	var histo = [256]uint{0}
   324  	var i uint
   325  	for i = 0; i < len; i += shouldMergeBlock_kSampleRate {
   326  		histo[data[i]]++
   327  	}
   328  	{
   329  		var total uint = (len + shouldMergeBlock_kSampleRate - 1) / shouldMergeBlock_kSampleRate
   330  		var r float64 = (fastLog2(total)+0.5)*float64(total) + 200
   331  		for i = 0; i < 256; i++ {
   332  			r -= float64(histo[i]) * (float64(depths[i]) + fastLog2(histo[i]))
   333  		}
   334  
   335  		return r >= 0.0
   336  	}
   337  }
   338  
   339  func shouldUseUncompressedMode(metablock_start []byte, next_emit []byte, insertlen uint, literal_ratio uint) bool {
   340  	var compressed uint = uint(-cap(next_emit) + cap(metablock_start))
   341  	if compressed*50 > insertlen {
   342  		return false
   343  	} else {
   344  		return literal_ratio > 980
   345  	}
   346  }
   347  
   348  func emitUncompressedMetaBlock1(begin []byte, end []byte, storage_ix_start uint, storage_ix *uint, storage []byte) {
   349  	var len uint = uint(-cap(end) + cap(begin))
   350  	rewindBitPosition1(storage_ix_start, storage_ix, storage)
   351  	storeMetaBlockHeader1(uint(len), true, storage_ix, storage)
   352  	*storage_ix = (*storage_ix + 7) &^ 7
   353  	copy(storage[*storage_ix>>3:], begin[:len])
   354  	*storage_ix += uint(len << 3)
   355  	storage[*storage_ix>>3] = 0
   356  }
   357  
   358  var kCmdHistoSeed = [128]uint32{
   359  	0,
   360  	1,
   361  	1,
   362  	1,
   363  	1,
   364  	1,
   365  	1,
   366  	1,
   367  	1,
   368  	1,
   369  	1,
   370  	1,
   371  	1,
   372  	1,
   373  	1,
   374  	1,
   375  	0,
   376  	0,
   377  	0,
   378  	1,
   379  	1,
   380  	1,
   381  	1,
   382  	1,
   383  	1,
   384  	1,
   385  	1,
   386  	1,
   387  	1,
   388  	1,
   389  	1,
   390  	1,
   391  	1,
   392  	1,
   393  	1,
   394  	1,
   395  	1,
   396  	1,
   397  	1,
   398  	1,
   399  	0,
   400  	1,
   401  	1,
   402  	1,
   403  	1,
   404  	1,
   405  	1,
   406  	1,
   407  	1,
   408  	1,
   409  	1,
   410  	1,
   411  	1,
   412  	1,
   413  	1,
   414  	1,
   415  	1,
   416  	1,
   417  	1,
   418  	1,
   419  	1,
   420  	1,
   421  	1,
   422  	1,
   423  	1,
   424  	0,
   425  	0,
   426  	0,
   427  	0,
   428  	0,
   429  	0,
   430  	0,
   431  	0,
   432  	0,
   433  	0,
   434  	0,
   435  	0,
   436  	0,
   437  	0,
   438  	0,
   439  	1,
   440  	1,
   441  	1,
   442  	1,
   443  	1,
   444  	1,
   445  	1,
   446  	1,
   447  	1,
   448  	1,
   449  	1,
   450  	1,
   451  	1,
   452  	1,
   453  	1,
   454  	1,
   455  	1,
   456  	1,
   457  	1,
   458  	1,
   459  	1,
   460  	1,
   461  	1,
   462  	1,
   463  	1,
   464  	1,
   465  	1,
   466  	1,
   467  	1,
   468  	1,
   469  	1,
   470  	1,
   471  	1,
   472  	1,
   473  	1,
   474  	1,
   475  	1,
   476  	1,
   477  	1,
   478  	1,
   479  	1,
   480  	1,
   481  	1,
   482  	1,
   483  	0,
   484  	0,
   485  	0,
   486  	0,
   487  }
   488  
   489  var compressFragmentFastImpl_kFirstBlockSize uint = 3 << 15
   490  var compressFragmentFastImpl_kMergeBlockSize uint = 1 << 16
   491  
   492  func compressFragmentFastImpl(in []byte, input_size uint, is_last bool, table []int, table_bits uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {
   493  	var cmd_histo [128]uint32
   494  	var ip_end int
   495  	var next_emit int = 0
   496  	var base_ip int = 0
   497  	var input int = 0
   498  	const kInputMarginBytes uint = windowGap
   499  	const kMinMatchLen uint = 5
   500  	var metablock_start int = input
   501  	var block_size uint = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)
   502  	var total_block_size uint = block_size
   503  	var mlen_storage_ix uint = *storage_ix + 3
   504  	var lit_depth [256]byte
   505  	var lit_bits [256]uint16
   506  	var literal_ratio uint
   507  	var ip int
   508  	var last_distance int
   509  	var shift uint = 64 - table_bits
   510  
   511  	/* "next_emit" is a pointer to the first byte that is not covered by a
   512  	   previous copy. Bytes between "next_emit" and the start of the next copy or
   513  	   the end of the input will be emitted as literal bytes. */
   514  
   515  	/* Save the start of the first block for position and distance computations.
   516  	 */
   517  
   518  	/* Save the bit position of the MLEN field of the meta-block header, so that
   519  	   we can update it later if we decide to extend this meta-block. */
   520  	storeMetaBlockHeader1(block_size, false, storage_ix, storage)
   521  
   522  	/* No block splits, no contexts. */
   523  	writeBits(13, 0, storage_ix, storage)
   524  
   525  	literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)
   526  	{
   527  		/* Store the pre-compressed command and distance prefix codes. */
   528  		var i uint
   529  		for i = 0; i+7 < *cmd_code_numbits; i += 8 {
   530  			writeBits(8, uint64(cmd_code[i>>3]), storage_ix, storage)
   531  		}
   532  	}
   533  
   534  	writeBits(*cmd_code_numbits&7, uint64(cmd_code[*cmd_code_numbits>>3]), storage_ix, storage)
   535  
   536  	/* Initialize the command and distance histograms. We will gather
   537  	   statistics of command and distance codes during the processing
   538  	   of this block and use it to update the command and distance
   539  	   prefix codes for the next block. */
   540  emit_commands:
   541  	copy(cmd_histo[:], kCmdHistoSeed[:])
   542  
   543  	/* "ip" is the input pointer. */
   544  	ip = input
   545  
   546  	last_distance = -1
   547  	ip_end = int(uint(input) + block_size)
   548  
   549  	if block_size >= kInputMarginBytes {
   550  		var len_limit uint = brotli_min_size_t(block_size-kMinMatchLen, input_size-kInputMarginBytes)
   551  		var ip_limit int = int(uint(input) + len_limit)
   552  		/* For the last block, we need to keep a 16 bytes margin so that we can be
   553  		   sure that all distances are at most window size - 16.
   554  		   For all other blocks, we only need to keep a margin of 5 bytes so that
   555  		   we don't go over the block size with a copy. */
   556  
   557  		var next_hash uint32
   558  		ip++
   559  		for next_hash = hash5(in[ip:], shift); ; {
   560  			var skip uint32 = 32
   561  			var next_ip int = ip
   562  			/* Step 1: Scan forward in the input looking for a 5-byte-long match.
   563  			   If we get close to exhausting the input then goto emit_remainder.
   564  
   565  			   Heuristic match skipping: If 32 bytes are scanned with no matches
   566  			   found, start looking only at every other byte. If 32 more bytes are
   567  			   scanned, look at every third byte, etc.. When a match is found,
   568  			   immediately go back to looking at every byte. This is a small loss
   569  			   (~5% performance, ~0.1% density) for compressible data due to more
   570  			   bookkeeping, but for non-compressible data (such as JPEG) it's a huge
   571  			   win since the compressor quickly "realizes" the data is incompressible
   572  			   and doesn't bother looking for matches everywhere.
   573  
   574  			   The "skip" variable keeps track of how many bytes there are since the
   575  			   last match; dividing it by 32 (i.e. right-shifting by five) gives the
   576  			   number of bytes to move ahead for each iteration. */
   577  
   578  			var candidate int
   579  			assert(next_emit < ip)
   580  
   581  		trawl:
   582  			for {
   583  				var hash uint32 = next_hash
   584  				var bytes_between_hash_lookups uint32 = skip >> 5
   585  				skip++
   586  				assert(hash == hash5(in[next_ip:], shift))
   587  				ip = next_ip
   588  				next_ip = int(uint32(ip) + bytes_between_hash_lookups)
   589  				if next_ip > ip_limit {
   590  					goto emit_remainder
   591  				}
   592  
   593  				next_hash = hash5(in[next_ip:], shift)
   594  				candidate = ip - last_distance
   595  				if isMatch5(in[ip:], in[candidate:]) {
   596  					if candidate < ip {
   597  						table[hash] = int(ip - base_ip)
   598  						break
   599  					}
   600  				}
   601  
   602  				candidate = base_ip + table[hash]
   603  				assert(candidate >= base_ip)
   604  				assert(candidate < ip)
   605  
   606  				table[hash] = int(ip - base_ip)
   607  				if isMatch5(in[ip:], in[candidate:]) {
   608  					break
   609  				}
   610  			}
   611  
   612  			/* Check copy distance. If candidate is not feasible, continue search.
   613  			   Checking is done outside of hot loop to reduce overhead. */
   614  			if ip-candidate > maxDistance_compress_fragment {
   615  				goto trawl
   616  			}
   617  
   618  			/* Step 2: Emit the found match together with the literal bytes from
   619  			   "next_emit" to the bit stream, and then see if we can find a next match
   620  			   immediately afterwards. Repeat until we find no match for the input
   621  			   without emitting some literal bytes. */
   622  			{
   623  				var base int = ip
   624  				/* > 0 */
   625  				var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)
   626  				var distance int = int(base - candidate)
   627  				/* We have a 5-byte match at ip, and we need to emit bytes in
   628  				   [next_emit, ip). */
   629  
   630  				var insert uint = uint(base - next_emit)
   631  				ip += int(matched)
   632  				if insert < 6210 {
   633  					emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   634  				} else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {
   635  					emitUncompressedMetaBlock1(in[metablock_start:], in[base:], mlen_storage_ix-3, storage_ix, storage)
   636  					input_size -= uint(base - input)
   637  					input = base
   638  					next_emit = input
   639  					goto next_block
   640  				} else {
   641  					emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   642  				}
   643  
   644  				emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
   645  				if distance == last_distance {
   646  					writeBits(uint(cmd_depth[64]), uint64(cmd_bits[64]), storage_ix, storage)
   647  					cmd_histo[64]++
   648  				} else {
   649  					emitDistance1(uint(distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   650  					last_distance = distance
   651  				}
   652  
   653  				emitCopyLenLastDistance1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   654  
   655  				next_emit = ip
   656  				if ip >= ip_limit {
   657  					goto emit_remainder
   658  				}
   659  
   660  				/* We could immediately start working at ip now, but to improve
   661  				   compression we first update "table" with the hashes of some positions
   662  				   within the last copy. */
   663  				{
   664  					var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])
   665  					var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)
   666  					var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)
   667  					table[prev_hash] = int(ip - base_ip - 3)
   668  					prev_hash = hashBytesAtOffset5(input_bytes, 1, shift)
   669  					table[prev_hash] = int(ip - base_ip - 2)
   670  					prev_hash = hashBytesAtOffset5(input_bytes, 2, shift)
   671  					table[prev_hash] = int(ip - base_ip - 1)
   672  
   673  					candidate = base_ip + table[cur_hash]
   674  					table[cur_hash] = int(ip - base_ip)
   675  				}
   676  			}
   677  
   678  			for isMatch5(in[ip:], in[candidate:]) {
   679  				var base int = ip
   680  				/* We have a 5-byte match at ip, and no need to emit any literal bytes
   681  				   prior to ip. */
   682  
   683  				var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)
   684  				if ip-candidate > maxDistance_compress_fragment {
   685  					break
   686  				}
   687  				ip += int(matched)
   688  				last_distance = int(base - candidate) /* > 0 */
   689  				emitCopyLen1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   690  				emitDistance1(uint(last_distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   691  
   692  				next_emit = ip
   693  				if ip >= ip_limit {
   694  					goto emit_remainder
   695  				}
   696  
   697  				/* We could immediately start working at ip now, but to improve
   698  				   compression we first update "table" with the hashes of some positions
   699  				   within the last copy. */
   700  				{
   701  					var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])
   702  					var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)
   703  					var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)
   704  					table[prev_hash] = int(ip - base_ip - 3)
   705  					prev_hash = hashBytesAtOffset5(input_bytes, 1, shift)
   706  					table[prev_hash] = int(ip - base_ip - 2)
   707  					prev_hash = hashBytesAtOffset5(input_bytes, 2, shift)
   708  					table[prev_hash] = int(ip - base_ip - 1)
   709  
   710  					candidate = base_ip + table[cur_hash]
   711  					table[cur_hash] = int(ip - base_ip)
   712  				}
   713  			}
   714  
   715  			ip++
   716  			next_hash = hash5(in[ip:], shift)
   717  		}
   718  	}
   719  
   720  emit_remainder:
   721  	assert(next_emit <= ip_end)
   722  	input += int(block_size)
   723  	input_size -= block_size
   724  	block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kMergeBlockSize)
   725  
   726  	/* Decide if we want to continue this meta-block instead of emitting the
   727  	   last insert-only command. */
   728  	if input_size > 0 && total_block_size+block_size <= 1<<20 && shouldMergeBlock(in[input:], block_size, lit_depth[:]) {
   729  		assert(total_block_size > 1<<16)
   730  
   731  		/* Update the size of the current meta-block and continue emitting commands.
   732  		   We can do this because the current size and the new size both have 5
   733  		   nibbles. */
   734  		total_block_size += block_size
   735  
   736  		updateBits(20, uint32(total_block_size-1), mlen_storage_ix, storage)
   737  		goto emit_commands
   738  	}
   739  
   740  	/* Emit the remaining bytes as literals. */
   741  	if next_emit < ip_end {
   742  		var insert uint = uint(ip_end - next_emit)
   743  		if insert < 6210 {
   744  			emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   745  			emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
   746  		} else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {
   747  			emitUncompressedMetaBlock1(in[metablock_start:], in[ip_end:], mlen_storage_ix-3, storage_ix, storage)
   748  		} else {
   749  			emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
   750  			emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
   751  		}
   752  	}
   753  
   754  	next_emit = ip_end
   755  
   756  	/* If we have more data, write a new meta-block header and prefix codes and
   757  	   then continue emitting commands. */
   758  next_block:
   759  	if input_size > 0 {
   760  		metablock_start = input
   761  		block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)
   762  		total_block_size = block_size
   763  
   764  		/* Save the bit position of the MLEN field of the meta-block header, so that
   765  		   we can update it later if we decide to extend this meta-block. */
   766  		mlen_storage_ix = *storage_ix + 3
   767  
   768  		storeMetaBlockHeader1(block_size, false, storage_ix, storage)
   769  
   770  		/* No block splits, no contexts. */
   771  		writeBits(13, 0, storage_ix, storage)
   772  
   773  		literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)
   774  		buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, storage_ix, storage)
   775  		goto emit_commands
   776  	}
   777  
   778  	if !is_last {
   779  		/* If this is not the last block, update the command and distance prefix
   780  		   codes for the next block and store the compressed forms. */
   781  		cmd_code[0] = 0
   782  
   783  		*cmd_code_numbits = 0
   784  		buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, cmd_code_numbits, cmd_code)
   785  	}
   786  }
   787  
   788  /* Compresses "input" string to the "*storage" buffer as one or more complete
   789     meta-blocks, and updates the "*storage_ix" bit position.
   790  
   791     If "is_last" is 1, emits an additional empty last meta-block.
   792  
   793     "cmd_depth" and "cmd_bits" contain the command and distance prefix codes
   794     (see comment in encode.h) used for the encoding of this input fragment.
   795     If "is_last" is 0, they are updated to reflect the statistics
   796     of this input fragment, to be used for the encoding of the next fragment.
   797  
   798     "*cmd_code_numbits" is the number of bits of the compressed representation
   799     of the command and distance prefix codes, and "cmd_code" is an array of
   800     at least "(*cmd_code_numbits + 7) >> 3" size that contains the compressed
   801     command and distance prefix codes. If "is_last" is 0, these are also
   802     updated to represent the updated "cmd_depth" and "cmd_bits".
   803  
   804     REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
   805     REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
   806     REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
   807     REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two
   808     OUTPUT: maximal copy distance <= |input_size|
   809     OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
   810  func compressFragmentFast(input []byte, input_size uint, is_last bool, table []int, table_size uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {
   811  	var initial_storage_ix uint = *storage_ix
   812  	var table_bits uint = uint(log2FloorNonZero(table_size))
   813  
   814  	if input_size == 0 {
   815  		assert(is_last)
   816  		writeBits(1, 1, storage_ix, storage) /* islast */
   817  		writeBits(1, 1, storage_ix, storage) /* isempty */
   818  		*storage_ix = (*storage_ix + 7) &^ 7
   819  		return
   820  	}
   821  
   822  	compressFragmentFastImpl(input, input_size, is_last, table, table_bits, cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage)
   823  
   824  	/* If output is larger than single uncompressed block, rewrite it. */
   825  	if *storage_ix-initial_storage_ix > 31+(input_size<<3) {
   826  		emitUncompressedMetaBlock1(input, input[input_size:], initial_storage_ix, storage_ix, storage)
   827  	}
   828  
   829  	if is_last {
   830  		writeBits(1, 1, storage_ix, storage) /* islast */
   831  		writeBits(1, 1, storage_ix, storage) /* isempty */
   832  		*storage_ix = (*storage_ix + 7) &^ 7
   833  	}
   834  }