github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/klauspost/compress/flate/snappy.go (about)

     1  // Copyright 2011 The Snappy-Go Authors. All rights reserved.
     2  // Modified for deflate by Klaus Post (c) 2015.
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package flate
     7  
     8  // We limit how far copy back-references can go, the same as the C++ code.
     9  const maxOffset = 1 << 15
    10  
    11  // emitLiteral writes a literal chunk and returns the number of bytes written.
    12  func emitLiteral(dst *tokens, lit []byte) {
    13  	ol := dst.n
    14  	for i, v := range lit {
    15  		dst.tokens[i+ol] = token(v)
    16  	}
    17  	dst.n += len(lit)
    18  }
    19  
    20  // emitCopy writes a copy chunk and returns the number of bytes written.
    21  func emitCopy(dst *tokens, offset, length int) {
    22  	dst.tokens[dst.n] = matchToken(uint32(length-3), uint32(offset-minOffsetSize))
    23  	dst.n++
    24  }
    25  
    26  type snappyEnc interface {
    27  	Encode(dst *tokens, src []byte)
    28  	Reset()
    29  }
    30  
    31  func newSnappy(level int) snappyEnc {
    32  	if useSSE42 {
    33  		e := &snappySSE4{snappyGen: snappyGen{cur: 1}}
    34  		switch level {
    35  		case 3:
    36  			e.enc = e.encodeL3
    37  			return e
    38  		}
    39  	}
    40  	e := &snappyGen{cur: 1}
    41  	switch level {
    42  	case 1:
    43  		e.enc = e.encodeL1
    44  	case 2:
    45  		e.enc = e.encodeL2
    46  	case 3:
    47  		e.enc = e.encodeL3
    48  	default:
    49  		panic("invalid level specified")
    50  	}
    51  	return e
    52  }
    53  
    54  const tableBits = 14             // Bits used in the table
    55  const tableSize = 1 << tableBits // Size of the table
    56  
    57  // snappyGen maintains the table for matches,
    58  // and the previous byte block for level 2.
    59  // This is the generic implementation.
    60  type snappyGen struct {
    61  	table [tableSize]int64
    62  	block [maxStoreBlockSize]byte
    63  	prev  []byte
    64  	cur   int
    65  	enc   func(dst *tokens, src []byte)
    66  }
    67  
    68  func (e *snappyGen) Encode(dst *tokens, src []byte) {
    69  	e.enc(dst, src)
    70  }
    71  
    72  // EncodeL1 uses Snappy-like compression, but stores as Huffman
    73  // blocks.
    74  func (e *snappyGen) encodeL1(dst *tokens, src []byte) {
    75  	// Return early if src is short.
    76  	if len(src) <= 4 {
    77  		if len(src) != 0 {
    78  			emitLiteral(dst, src)
    79  		}
    80  		e.cur += 4
    81  		return
    82  	}
    83  
    84  	// Ensure that e.cur doesn't wrap, mainly an issue on 32 bits.
    85  	if e.cur > 1<<30 {
    86  		e.cur = 1
    87  	}
    88  
    89  	// Iterate over the source bytes.
    90  	var (
    91  		s   int // The iterator position.
    92  		t   int // The last position with the same hash as s.
    93  		lit int // The start position of any pending literal bytes.
    94  	)
    95  
    96  	for s+3 < len(src) {
    97  		// Update the hash table.
    98  		b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3]
    99  		h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24
   100  		p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)]
   101  		// We need to to store values in [-1, inf) in table.
   102  		// To save some initialization time, we make sure that
   103  		// e.cur is never zero.
   104  		t, *p = int(*p)-e.cur, int64(s+e.cur)
   105  
   106  		offset := uint(s - t - 1)
   107  
   108  		// If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte.
   109  		if t < 0 || offset >= (maxOffset-1) || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] {
   110  			// Skip 1 byte for 16 consecutive missed.
   111  			s += 1 + ((s - lit) >> 4)
   112  			continue
   113  		}
   114  		// Otherwise, we have a match. First, emit any pending literal bytes.
   115  		if lit != s {
   116  			emitLiteral(dst, src[lit:s])
   117  		}
   118  		// Extend the match to be as long as possible.
   119  		s0 := s
   120  		s1 := s + maxMatchLength
   121  		if s1 > len(src) {
   122  			s1 = len(src)
   123  		}
   124  		s, t = s+4, t+4
   125  		for s < s1 && src[s] == src[t] {
   126  			s++
   127  			t++
   128  		}
   129  		// Emit the copied bytes.
   130  		// inlined: emitCopy(dst, s-t, s-s0)
   131  
   132  		dst.tokens[dst.n] = matchToken(uint32(s-s0-3), uint32(s-t-minOffsetSize))
   133  		dst.n++
   134  		lit = s
   135  	}
   136  
   137  	// Emit any final pending literal bytes and return.
   138  	if lit != len(src) {
   139  		emitLiteral(dst, src[lit:])
   140  	}
   141  	e.cur += len(src)
   142  }
   143  
   144  // EncodeL2 uses a similar algorithm to level 1, but is capable
   145  // of matching across blocks giving better compression at a small slowdown.
   146  func (e *snappyGen) encodeL2(dst *tokens, src []byte) {
   147  	// Return early if src is short.
   148  	if len(src) <= 4 {
   149  		if len(src) != 0 {
   150  			emitLiteral(dst, src)
   151  		}
   152  		e.prev = nil
   153  		e.cur += len(src)
   154  		return
   155  	}
   156  
   157  	// Ensure that e.cur doesn't wrap, mainly an issue on 32 bits.
   158  	if e.cur > 1<<30 {
   159  		e.cur = 1
   160  	}
   161  
   162  	// Iterate over the source bytes.
   163  	var (
   164  		s   int // The iterator position.
   165  		t   int // The last position with the same hash as s.
   166  		lit int // The start position of any pending literal bytes.
   167  	)
   168  
   169  	for s+3 < len(src) {
   170  		// Update the hash table.
   171  		b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3]
   172  		h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24
   173  		p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)]
   174  		// We need to to store values in [-1, inf) in table.
   175  		// To save some initialization time, we make sure that
   176  		// e.cur is never zero.
   177  		t, *p = int(*p)-e.cur, int64(s+e.cur)
   178  
   179  		// If t is positive, the match starts in the current block
   180  		if t >= 0 {
   181  
   182  			offset := uint(s - t - 1)
   183  			// Check that the offset is valid and that we match at least 4 bytes
   184  			if offset >= (maxOffset-1) || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] {
   185  				// Skip 1 byte for 32 consecutive missed.
   186  				s += 1 + ((s - lit) >> 5)
   187  				continue
   188  			}
   189  			// Otherwise, we have a match. First, emit any pending literal bytes.
   190  			if lit != s {
   191  				emitLiteral(dst, src[lit:s])
   192  			}
   193  			// Extend the match to be as long as possible.
   194  			s0 := s
   195  			s1 := s + maxMatchLength
   196  			if s1 > len(src) {
   197  				s1 = len(src)
   198  			}
   199  			s, t = s+4, t+4
   200  			for s < s1 && src[s] == src[t] {
   201  				s++
   202  				t++
   203  			}
   204  			// Emit the copied bytes.
   205  			// inlined: emitCopy(dst, s-t, s-s0)
   206  			dst.tokens[dst.n] = matchToken(uint32(s-s0-3), uint32(s-t-minOffsetSize))
   207  			dst.n++
   208  			lit = s
   209  			continue
   210  		}
   211  		// We found a match in the previous block.
   212  		tp := len(e.prev) + t
   213  		if tp < 0 || t > -5 || s-t >= maxOffset || b0 != e.prev[tp] || b1 != e.prev[tp+1] || b2 != e.prev[tp+2] || b3 != e.prev[tp+3] {
   214  			// Skip 1 byte for 32 consecutive missed.
   215  			s += 1 + ((s - lit) >> 5)
   216  			continue
   217  		}
   218  		// Otherwise, we have a match. First, emit any pending literal bytes.
   219  		if lit != s {
   220  			emitLiteral(dst, src[lit:s])
   221  		}
   222  		// Extend the match to be as long as possible.
   223  		s0 := s
   224  		s1 := s + maxMatchLength
   225  		if s1 > len(src) {
   226  			s1 = len(src)
   227  		}
   228  		s, tp = s+4, tp+4
   229  		for s < s1 && src[s] == e.prev[tp] {
   230  			s++
   231  			tp++
   232  			if tp == len(e.prev) {
   233  				t = 0
   234  				// continue in current buffer
   235  				for s < s1 && src[s] == src[t] {
   236  					s++
   237  					t++
   238  				}
   239  				goto l
   240  			}
   241  		}
   242  	l:
   243  		// Emit the copied bytes.
   244  		if t < 0 {
   245  			t = tp - len(e.prev)
   246  		}
   247  		dst.tokens[dst.n] = matchToken(uint32(s-s0-3), uint32(s-t-minOffsetSize))
   248  		dst.n++
   249  		lit = s
   250  
   251  	}
   252  
   253  	// Emit any final pending literal bytes and return.
   254  	if lit != len(src) {
   255  		emitLiteral(dst, src[lit:])
   256  	}
   257  	e.cur += len(src)
   258  	// Store this block, if it was full length.
   259  	if len(src) == maxStoreBlockSize {
   260  		copy(e.block[:], src)
   261  		e.prev = e.block[:len(src)]
   262  	} else {
   263  		e.prev = nil
   264  	}
   265  }
   266  
   267  // EncodeL3 uses a similar algorithm to level 2, but is capable
   268  // will keep two matches per hash.
   269  // Both hashes are checked if the first isn't ok, and the longest is selected.
   270  func (e *snappyGen) encodeL3(dst *tokens, src []byte) {
   271  	// Return early if src is short.
   272  	if len(src) <= 4 {
   273  		if len(src) != 0 {
   274  			emitLiteral(dst, src)
   275  		}
   276  		e.prev = nil
   277  		e.cur += len(src)
   278  		return
   279  	}
   280  
   281  	// Ensure that e.cur doesn't wrap, mainly an issue on 32 bits.
   282  	if e.cur > 1<<30 {
   283  		e.cur = 1
   284  	}
   285  
   286  	// Iterate over the source bytes.
   287  	var (
   288  		s   int // The iterator position.
   289  		lit int // The start position of any pending literal bytes.
   290  	)
   291  
   292  	for s+3 < len(src) {
   293  		// Update the hash table.
   294  		h := uint32(src[s]) | uint32(src[s+1])<<8 | uint32(src[s+2])<<16 | uint32(src[s+3])<<24
   295  		p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)]
   296  		tmp := *p
   297  		p1 := int(tmp & 0xffffffff) // Closest match position
   298  		p2 := int(tmp >> 32)        // Furthest match position
   299  
   300  		// We need to to store values in [-1, inf) in table.
   301  		// To save some initialization time, we make sure that
   302  		// e.cur is never zero.
   303  		t1 := p1 - e.cur
   304  
   305  		var l2 int
   306  		var t2 int
   307  		l1 := e.matchlen(s, t1, src)
   308  		// If fist match was ok, don't do the second.
   309  		if l1 < 16 {
   310  			t2 = p2 - e.cur
   311  			l2 = e.matchlen(s, t2, src)
   312  
   313  			// If both are short, continue
   314  			if l1 < 4 && l2 < 4 {
   315  				// Update hash table
   316  				*p = int64(s+e.cur) | (int64(p1) << 32)
   317  				// Skip 1 byte for 32 consecutive missed.
   318  				s += 1 + ((s - lit) >> 5)
   319  				continue
   320  			}
   321  		}
   322  
   323  		// Otherwise, we have a match. First, emit any pending literal bytes.
   324  		if lit != s {
   325  			emitLiteral(dst, src[lit:s])
   326  		}
   327  		// Update hash table
   328  		*p = int64(s+e.cur) | (int64(p1) << 32)
   329  
   330  		// Store the longest match l1 will be closest, so we prefer that if equal length
   331  		if l1 >= l2 {
   332  			dst.tokens[dst.n] = matchToken(uint32(l1-3), uint32(s-t1-minOffsetSize))
   333  			s += l1
   334  		} else {
   335  			dst.tokens[dst.n] = matchToken(uint32(l2-3), uint32(s-t2-minOffsetSize))
   336  			s += l2
   337  		}
   338  		dst.n++
   339  		lit = s
   340  	}
   341  
   342  	// Emit any final pending literal bytes and return.
   343  	if lit != len(src) {
   344  		emitLiteral(dst, src[lit:])
   345  	}
   346  	e.cur += len(src)
   347  	// Store this block, if it was full length.
   348  	if len(src) == maxStoreBlockSize {
   349  		copy(e.block[:], src)
   350  		e.prev = e.block[:len(src)]
   351  	} else {
   352  		e.prev = nil
   353  	}
   354  }
   355  
   356  func (e *snappyGen) matchlen(s, t int, src []byte) int {
   357  	// If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte.
   358  	offset := uint(s - t - 1)
   359  
   360  	// If we are inside the current block
   361  	if t >= 0 {
   362  		if offset >= (maxOffset-1) ||
   363  			src[s] != src[t] || src[s+1] != src[t+1] ||
   364  			src[s+2] != src[t+2] || src[s+3] != src[t+3] {
   365  			return 0
   366  		}
   367  		// Extend the match to be as long as possible.
   368  		s0 := s
   369  		s1 := s + maxMatchLength
   370  		if s1 > len(src) {
   371  			s1 = len(src)
   372  		}
   373  		s, t = s+4, t+4
   374  		for s < s1 && src[s] == src[t] {
   375  			s++
   376  			t++
   377  		}
   378  		return s - s0
   379  	}
   380  
   381  	// We found a match in the previous block.
   382  	tp := len(e.prev) + t
   383  	if tp < 0 || offset >= (maxOffset-1) || t > -5 ||
   384  		src[s] != e.prev[tp] || src[s+1] != e.prev[tp+1] ||
   385  		src[s+2] != e.prev[tp+2] || src[s+3] != e.prev[tp+3] {
   386  		return 0
   387  	}
   388  
   389  	// Extend the match to be as long as possible.
   390  	s0 := s
   391  	s1 := s + maxMatchLength
   392  	if s1 > len(src) {
   393  		s1 = len(src)
   394  	}
   395  	s, tp = s+4, tp+4
   396  	for s < s1 && src[s] == e.prev[tp] {
   397  		s++
   398  		tp++
   399  		if tp == len(e.prev) {
   400  			t = 0
   401  			// continue in current buffer
   402  			for s < s1 && src[s] == src[t] {
   403  				s++
   404  				t++
   405  			}
   406  			return s - s0
   407  		}
   408  	}
   409  	return s - s0
   410  }
   411  
   412  // Reset the encoding table.
   413  func (e *snappyGen) Reset() {
   414  	e.prev = nil
   415  }
   416  
   417  // snappySSE4 extends snappyGen.
   418  // This implementation can use SSE 4.2 for length matching.
   419  type snappySSE4 struct {
   420  	snappyGen
   421  }
   422  
   423  // EncodeL3 uses a similar algorithm to level 2,
   424  // but will keep two matches per hash.
   425  // Both hashes are checked if the first isn't ok, and the longest is selected.
   426  func (e *snappySSE4) encodeL3(dst *tokens, src []byte) {
   427  	// Return early if src is short.
   428  	if len(src) <= 4 {
   429  		if len(src) != 0 {
   430  			emitLiteral(dst, src)
   431  		}
   432  		e.prev = nil
   433  		e.cur += len(src)
   434  		return
   435  	}
   436  
   437  	// Ensure that e.cur doesn't wrap, mainly an issue on 32 bits.
   438  	if e.cur > 1<<30 {
   439  		e.cur = 1
   440  	}
   441  
   442  	// Iterate over the source bytes.
   443  	var (
   444  		s   int // The iterator position.
   445  		lit int // The start position of any pending literal bytes.
   446  	)
   447  
   448  	for s+3 < len(src) {
   449  		// Load potential matches from hash table.
   450  		h := uint32(src[s]) | uint32(src[s+1])<<8 | uint32(src[s+2])<<16 | uint32(src[s+3])<<24
   451  		p := &e.table[(h*0x1e35a7bd)>>(32-tableBits)]
   452  		tmp := *p
   453  		p1 := int(tmp & 0xffffffff) // Closest match position
   454  		p2 := int(tmp >> 32)        // Furthest match position
   455  
   456  		// We need to to store values in [-1, inf) in table.
   457  		// To save some initialization time, we make sure that
   458  		// e.cur is never zero.
   459  		t1 := int(p1) - e.cur
   460  
   461  		var l2 int
   462  		var t2 int
   463  		l1 := e.matchlen(s, t1, src)
   464  		// If fist match was ok, don't do the second.
   465  		if l1 < 16 {
   466  			t2 = int(p2) - e.cur
   467  			l2 = e.matchlen(s, t2, src)
   468  
   469  			// If both are short, continue
   470  			if l1 < 4 && l2 < 4 {
   471  				// Update hash table
   472  				*p = int64(s+e.cur) | (int64(p1) << 32)
   473  				// Skip 1 byte for 32 consecutive missed.
   474  				s += 1 + ((s - lit) >> 5)
   475  				continue
   476  			}
   477  		}
   478  
   479  		// Otherwise, we have a match. First, emit any pending literal bytes.
   480  		if lit != s {
   481  			emitLiteral(dst, src[lit:s])
   482  		}
   483  		// Update hash table
   484  		*p = int64(s+e.cur) | (int64(p1) << 32)
   485  
   486  		// Store the longest match l1 will be closest, so we prefer that if equal length
   487  		if l1 >= l2 {
   488  			dst.tokens[dst.n] = matchToken(uint32(l1-3), uint32(s-t1-minOffsetSize))
   489  			s += l1
   490  		} else {
   491  			dst.tokens[dst.n] = matchToken(uint32(l2-3), uint32(s-t2-minOffsetSize))
   492  			s += l2
   493  		}
   494  		dst.n++
   495  		lit = s
   496  	}
   497  
   498  	// Emit any final pending literal bytes and return.
   499  	if lit != len(src) {
   500  		emitLiteral(dst, src[lit:])
   501  	}
   502  	e.cur += len(src)
   503  	// Store this block, if it was full length.
   504  	if len(src) == maxStoreBlockSize {
   505  		copy(e.block[:], src)
   506  		e.prev = e.block[:len(src)]
   507  	} else {
   508  		e.prev = nil
   509  	}
   510  }
   511  
   512  func (e *snappySSE4) matchlen(s, t int, src []byte) int {
   513  	// If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte.
   514  	offset := uint(s - t - 1)
   515  
   516  	// If we are inside the current block
   517  	if t >= 0 {
   518  		if offset >= (maxOffset - 1) {
   519  			return 0
   520  		}
   521  		length := len(src) - s
   522  		if length > maxMatchLength {
   523  			length = maxMatchLength
   524  		}
   525  		// Extend the match to be as long as possible.
   526  		return matchLenSSE4(src[t:], src[s:], length)
   527  	}
   528  
   529  	// We found a match in the previous block.
   530  	tp := len(e.prev) + t
   531  	if tp < 0 || offset >= (maxOffset-1) || t > -5 ||
   532  		src[s] != e.prev[tp] || src[s+1] != e.prev[tp+1] ||
   533  		src[s+2] != e.prev[tp+2] || src[s+3] != e.prev[tp+3] {
   534  		return 0
   535  	}
   536  
   537  	// Extend the match to be as long as possible.
   538  	s0 := s
   539  	s1 := s + maxMatchLength
   540  	if s1 > len(src) {
   541  		s1 = len(src)
   542  	}
   543  	s, tp = s+4, tp+4
   544  	for s < s1 && src[s] == e.prev[tp] {
   545  		s++
   546  		tp++
   547  		if tp == len(e.prev) {
   548  			t = 0
   549  			// continue in current buffer
   550  			for s < s1 && src[s] == src[t] {
   551  				s++
   552  				t++
   553  			}
   554  			return s - s0
   555  		}
   556  	}
   557  	return s - s0
   558  }