fast_encoder.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. package flate
  6. import (
  7. "encoding/binary"
  8. "fmt"
  9. )
  10. type fastEnc interface {
  11. Encode(dst *tokens, src []byte)
  12. Reset()
  13. }
  14. func newFastEnc(level int) fastEnc {
  15. switch level {
  16. case 1:
  17. return &fastEncL1{fastGen: fastGen{cur: maxStoreBlockSize}}
  18. case 2:
  19. return &fastEncL2{fastGen: fastGen{cur: maxStoreBlockSize}}
  20. case 3:
  21. return &fastEncL3{fastGen: fastGen{cur: maxStoreBlockSize}}
  22. case 4:
  23. return &fastEncL4{fastGen: fastGen{cur: maxStoreBlockSize}}
  24. case 5:
  25. return &fastEncL5{fastGen: fastGen{cur: maxStoreBlockSize}}
  26. case 6:
  27. return &fastEncL6{fastGen: fastGen{cur: maxStoreBlockSize}}
  28. default:
  29. panic("invalid level specified")
  30. }
  31. }
  32. const (
  33. tableBits = 15 // Bits used in the table
  34. tableSize = 1 << tableBits // Size of the table
  35. tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
  36. baseMatchOffset = 1 // The smallest match offset
  37. baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5
  38. maxMatchOffset = 1 << 15 // The largest match offset
  39. bTableBits = 17 // Bits used in the big tables
  40. bTableSize = 1 << bTableBits // Size of the table
  41. allocHistory = maxStoreBlockSize * 5 // Size to preallocate for history.
  42. bufferReset = (1 << 31) - allocHistory - maxStoreBlockSize - 1 // Reset the buffer offset when reaching this.
  43. )
  44. const (
  45. prime3bytes = 506832829
  46. prime4bytes = 2654435761
  47. prime5bytes = 889523592379
  48. prime6bytes = 227718039650203
  49. prime7bytes = 58295818150454627
  50. prime8bytes = 0xcf1bbcdcb7a56463
  51. )
  52. func load3232(b []byte, i int32) uint32 {
  53. return binary.LittleEndian.Uint32(b[i:])
  54. }
  55. func load6432(b []byte, i int32) uint64 {
  56. return binary.LittleEndian.Uint64(b[i:])
  57. }
  58. type tableEntry struct {
  59. offset int32
  60. }
  61. // fastGen maintains the table for matches,
  62. // and the previous byte block for level 2.
  63. // This is the generic implementation.
  64. type fastGen struct {
  65. hist []byte
  66. cur int32
  67. }
  68. func (e *fastGen) addBlock(src []byte) int32 {
  69. // check if we have space already
  70. if len(e.hist)+len(src) > cap(e.hist) {
  71. if cap(e.hist) == 0 {
  72. e.hist = make([]byte, 0, allocHistory)
  73. } else {
  74. if cap(e.hist) < maxMatchOffset*2 {
  75. panic("unexpected buffer size")
  76. }
  77. // Move down
  78. offset := int32(len(e.hist)) - maxMatchOffset
  79. // copy(e.hist[0:maxMatchOffset], e.hist[offset:])
  80. *(*[maxMatchOffset]byte)(e.hist) = *(*[maxMatchOffset]byte)(e.hist[offset:])
  81. e.cur += offset
  82. e.hist = e.hist[:maxMatchOffset]
  83. }
  84. }
  85. s := int32(len(e.hist))
  86. e.hist = append(e.hist, src...)
  87. return s
  88. }
  89. type tableEntryPrev struct {
  90. Cur tableEntry
  91. Prev tableEntry
  92. }
  93. // hash7 returns the hash of the lowest 7 bytes of u to fit in a hash table with h bits.
  94. // Preferably h should be a constant and should always be <64.
  95. func hash7(u uint64, h uint8) uint32 {
  96. return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & reg8SizeMask64))
  97. }
  98. // hashLen returns a hash of the lowest mls bytes of with length output bits.
  99. // mls must be >=3 and <=8. Any other value will return hash for 4 bytes.
  100. // length should always be < 32.
  101. // Preferably length and mls should be a constant for inlining.
  102. func hashLen(u uint64, length, mls uint8) uint32 {
  103. switch mls {
  104. case 3:
  105. return (uint32(u<<8) * prime3bytes) >> (32 - length)
  106. case 5:
  107. return uint32(((u << (64 - 40)) * prime5bytes) >> (64 - length))
  108. case 6:
  109. return uint32(((u << (64 - 48)) * prime6bytes) >> (64 - length))
  110. case 7:
  111. return uint32(((u << (64 - 56)) * prime7bytes) >> (64 - length))
  112. case 8:
  113. return uint32((u * prime8bytes) >> (64 - length))
  114. default:
  115. return (uint32(u) * prime4bytes) >> (32 - length)
  116. }
  117. }
  118. // matchlen will return the match length between offsets and t in src.
  119. // The maximum length returned is maxMatchLength - 4.
  120. // It is assumed that s > t, that t >=0 and s < len(src).
  121. func (e *fastGen) matchlen(s, t int32, src []byte) int32 {
  122. if debugDecode {
  123. if t >= s {
  124. panic(fmt.Sprint("t >=s:", t, s))
  125. }
  126. if int(s) >= len(src) {
  127. panic(fmt.Sprint("s >= len(src):", s, len(src)))
  128. }
  129. if t < 0 {
  130. panic(fmt.Sprint("t < 0:", t))
  131. }
  132. if s-t > maxMatchOffset {
  133. panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
  134. }
  135. }
  136. s1 := int(s) + maxMatchLength - 4
  137. if s1 > len(src) {
  138. s1 = len(src)
  139. }
  140. // Extend the match to be as long as possible.
  141. return int32(matchLen(src[s:s1], src[t:]))
  142. }
  143. // matchlenLong will return the match length between offsets and t in src.
  144. // It is assumed that s > t, that t >=0 and s < len(src).
  145. func (e *fastGen) matchlenLong(s, t int32, src []byte) int32 {
  146. if debugDeflate {
  147. if t >= s {
  148. panic(fmt.Sprint("t >=s:", t, s))
  149. }
  150. if int(s) >= len(src) {
  151. panic(fmt.Sprint("s >= len(src):", s, len(src)))
  152. }
  153. if t < 0 {
  154. panic(fmt.Sprint("t < 0:", t))
  155. }
  156. if s-t > maxMatchOffset {
  157. panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
  158. }
  159. }
  160. // Extend the match to be as long as possible.
  161. return int32(matchLen(src[s:], src[t:]))
  162. }
  163. // Reset the encoding table.
  164. func (e *fastGen) Reset() {
  165. if cap(e.hist) < allocHistory {
  166. e.hist = make([]byte, 0, allocHistory)
  167. }
  168. // We offset current position so everything will be out of reach.
  169. // If we are above the buffer reset it will be cleared anyway since len(hist) == 0.
  170. if e.cur <= bufferReset {
  171. e.cur += maxMatchOffset + int32(len(e.hist))
  172. }
  173. e.hist = e.hist[:0]
  174. }