Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

899 řádky
23 KiB

  1. // Copyright 2019+ Klaus Post. All rights reserved.
  2. // License information can be found in the LICENSE file.
  3. // Based on work by Yann Collet, released under BSD License.
  4. package zstd
  5. import (
  6. "fmt"
  7. )
  8. const (
  9. tableBits = 15 // Bits used in the table
  10. tableSize = 1 << tableBits // Size of the table
  11. tableShardCnt = 1 << (tableBits - dictShardBits) // Number of shards in the table
  12. tableShardSize = tableSize / tableShardCnt // Size of an individual shard
  13. tableFastHashLen = 6
  14. tableMask = tableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
  15. maxMatchLength = 131074
  16. )
  17. type tableEntry struct {
  18. val uint32
  19. offset int32
  20. }
  21. type fastEncoder struct {
  22. fastBase
  23. table [tableSize]tableEntry
  24. }
  25. type fastEncoderDict struct {
  26. fastEncoder
  27. dictTable []tableEntry
  28. tableShardDirty [tableShardCnt]bool
  29. allDirty bool
  30. }
  31. // Encode mimmics functionality in zstd_fast.c
  32. func (e *fastEncoder) Encode(blk *blockEnc, src []byte) {
  33. const (
  34. inputMargin = 8
  35. minNonLiteralBlockSize = 1 + 1 + inputMargin
  36. )
  37. // Protect against e.cur wraparound.
  38. for e.cur >= bufferReset {
  39. if len(e.hist) == 0 {
  40. for i := range e.table[:] {
  41. e.table[i] = tableEntry{}
  42. }
  43. e.cur = e.maxMatchOff
  44. break
  45. }
  46. // Shift down everything in the table that isn't already too far away.
  47. minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
  48. for i := range e.table[:] {
  49. v := e.table[i].offset
  50. if v < minOff {
  51. v = 0
  52. } else {
  53. v = v - e.cur + e.maxMatchOff
  54. }
  55. e.table[i].offset = v
  56. }
  57. e.cur = e.maxMatchOff
  58. break
  59. }
  60. s := e.addBlock(src)
  61. blk.size = len(src)
  62. if len(src) < minNonLiteralBlockSize {
  63. blk.extraLits = len(src)
  64. blk.literals = blk.literals[:len(src)]
  65. copy(blk.literals, src)
  66. return
  67. }
  68. // Override src
  69. src = e.hist
  70. sLimit := int32(len(src)) - inputMargin
  71. // stepSize is the number of bytes to skip on every main loop iteration.
  72. // It should be >= 2.
  73. const stepSize = 2
  74. // TEMPLATE
  75. const hashLog = tableBits
  76. // seems global, but would be nice to tweak.
  77. const kSearchStrength = 6
  78. // nextEmit is where in src the next emitLiteral should start from.
  79. nextEmit := s
  80. cv := load6432(src, s)
  81. // Relative offsets
  82. offset1 := int32(blk.recentOffsets[0])
  83. offset2 := int32(blk.recentOffsets[1])
  84. addLiterals := func(s *seq, until int32) {
  85. if until == nextEmit {
  86. return
  87. }
  88. blk.literals = append(blk.literals, src[nextEmit:until]...)
  89. s.litLen = uint32(until - nextEmit)
  90. }
  91. if debugEncoder {
  92. println("recent offsets:", blk.recentOffsets)
  93. }
  94. encodeLoop:
  95. for {
  96. // t will contain the match offset when we find one.
  97. // When existing the search loop, we have already checked 4 bytes.
  98. var t int32
  99. // We will not use repeat offsets across blocks.
  100. // By not using them for the first 3 matches
  101. canRepeat := len(blk.sequences) > 2
  102. for {
  103. if debugAsserts && canRepeat && offset1 == 0 {
  104. panic("offset0 was 0")
  105. }
  106. nextHash := hashLen(cv, hashLog, tableFastHashLen)
  107. nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
  108. candidate := e.table[nextHash]
  109. candidate2 := e.table[nextHash2]
  110. repIndex := s - offset1 + 2
  111. e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
  112. e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
  113. if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) {
  114. // Consider history as well.
  115. var seq seq
  116. var length int32
  117. length = 4 + e.matchlen(s+6, repIndex+4, src)
  118. seq.matchLen = uint32(length - zstdMinMatch)
  119. // We might be able to match backwards.
  120. // Extend as long as we can.
  121. start := s + 2
  122. // We end the search early, so we don't risk 0 literals
  123. // and have to do special offset treatment.
  124. startLimit := nextEmit + 1
  125. sMin := s - e.maxMatchOff
  126. if sMin < 0 {
  127. sMin = 0
  128. }
  129. for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
  130. repIndex--
  131. start--
  132. seq.matchLen++
  133. }
  134. addLiterals(&seq, start)
  135. // rep 0
  136. seq.offset = 1
  137. if debugSequences {
  138. println("repeat sequence", seq, "next s:", s)
  139. }
  140. blk.sequences = append(blk.sequences, seq)
  141. s += length + 2
  142. nextEmit = s
  143. if s >= sLimit {
  144. if debugEncoder {
  145. println("repeat ended", s, length)
  146. }
  147. break encodeLoop
  148. }
  149. cv = load6432(src, s)
  150. continue
  151. }
  152. coffset0 := s - (candidate.offset - e.cur)
  153. coffset1 := s - (candidate2.offset - e.cur) + 1
  154. if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
  155. // found a regular match
  156. t = candidate.offset - e.cur
  157. if debugAsserts && s <= t {
  158. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  159. }
  160. if debugAsserts && s-t > e.maxMatchOff {
  161. panic("s - t >e.maxMatchOff")
  162. }
  163. break
  164. }
  165. if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
  166. // found a regular match
  167. t = candidate2.offset - e.cur
  168. s++
  169. if debugAsserts && s <= t {
  170. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  171. }
  172. if debugAsserts && s-t > e.maxMatchOff {
  173. panic("s - t >e.maxMatchOff")
  174. }
  175. if debugAsserts && t < 0 {
  176. panic("t<0")
  177. }
  178. break
  179. }
  180. s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
  181. if s >= sLimit {
  182. break encodeLoop
  183. }
  184. cv = load6432(src, s)
  185. }
  186. // A 4-byte match has been found. We'll later see if more than 4 bytes.
  187. offset2 = offset1
  188. offset1 = s - t
  189. if debugAsserts && s <= t {
  190. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  191. }
  192. if debugAsserts && canRepeat && int(offset1) > len(src) {
  193. panic("invalid offset")
  194. }
  195. // Extend the 4-byte match as long as possible.
  196. l := e.matchlen(s+4, t+4, src) + 4
  197. // Extend backwards
  198. tMin := s - e.maxMatchOff
  199. if tMin < 0 {
  200. tMin = 0
  201. }
  202. for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
  203. s--
  204. t--
  205. l++
  206. }
  207. // Write our sequence.
  208. var seq seq
  209. seq.litLen = uint32(s - nextEmit)
  210. seq.matchLen = uint32(l - zstdMinMatch)
  211. if seq.litLen > 0 {
  212. blk.literals = append(blk.literals, src[nextEmit:s]...)
  213. }
  214. // Don't use repeat offsets
  215. seq.offset = uint32(s-t) + 3
  216. s += l
  217. if debugSequences {
  218. println("sequence", seq, "next s:", s)
  219. }
  220. blk.sequences = append(blk.sequences, seq)
  221. nextEmit = s
  222. if s >= sLimit {
  223. break encodeLoop
  224. }
  225. cv = load6432(src, s)
  226. // Check offset 2
  227. if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) {
  228. // We have at least 4 byte match.
  229. // No need to check backwards. We come straight from a match
  230. l := 4 + e.matchlen(s+4, o2+4, src)
  231. // Store this, since we have it.
  232. nextHash := hashLen(cv, hashLog, tableFastHashLen)
  233. e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
  234. seq.matchLen = uint32(l) - zstdMinMatch
  235. seq.litLen = 0
  236. // Since litlen is always 0, this is offset 1.
  237. seq.offset = 1
  238. s += l
  239. nextEmit = s
  240. if debugSequences {
  241. println("sequence", seq, "next s:", s)
  242. }
  243. blk.sequences = append(blk.sequences, seq)
  244. // Swap offset 1 and 2.
  245. offset1, offset2 = offset2, offset1
  246. if s >= sLimit {
  247. break encodeLoop
  248. }
  249. // Prepare next loop.
  250. cv = load6432(src, s)
  251. }
  252. }
  253. if int(nextEmit) < len(src) {
  254. blk.literals = append(blk.literals, src[nextEmit:]...)
  255. blk.extraLits = len(src) - int(nextEmit)
  256. }
  257. blk.recentOffsets[0] = uint32(offset1)
  258. blk.recentOffsets[1] = uint32(offset2)
  259. if debugEncoder {
  260. println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
  261. }
  262. }
  263. // EncodeNoHist will encode a block with no history and no following blocks.
  264. // Most notable difference is that src will not be copied for history and
  265. // we do not need to check for max match length.
  266. func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
  267. const (
  268. inputMargin = 8
  269. minNonLiteralBlockSize = 1 + 1 + inputMargin
  270. )
  271. if debugEncoder {
  272. if len(src) > maxBlockSize {
  273. panic("src too big")
  274. }
  275. }
  276. // Protect against e.cur wraparound.
  277. if e.cur >= bufferReset {
  278. for i := range e.table[:] {
  279. e.table[i] = tableEntry{}
  280. }
  281. e.cur = e.maxMatchOff
  282. }
  283. s := int32(0)
  284. blk.size = len(src)
  285. if len(src) < minNonLiteralBlockSize {
  286. blk.extraLits = len(src)
  287. blk.literals = blk.literals[:len(src)]
  288. copy(blk.literals, src)
  289. return
  290. }
  291. sLimit := int32(len(src)) - inputMargin
  292. // stepSize is the number of bytes to skip on every main loop iteration.
  293. // It should be >= 2.
  294. const stepSize = 2
  295. // TEMPLATE
  296. const hashLog = tableBits
  297. // seems global, but would be nice to tweak.
  298. const kSearchStrength = 6
  299. // nextEmit is where in src the next emitLiteral should start from.
  300. nextEmit := s
  301. cv := load6432(src, s)
  302. // Relative offsets
  303. offset1 := int32(blk.recentOffsets[0])
  304. offset2 := int32(blk.recentOffsets[1])
  305. addLiterals := func(s *seq, until int32) {
  306. if until == nextEmit {
  307. return
  308. }
  309. blk.literals = append(blk.literals, src[nextEmit:until]...)
  310. s.litLen = uint32(until - nextEmit)
  311. }
  312. if debugEncoder {
  313. println("recent offsets:", blk.recentOffsets)
  314. }
  315. encodeLoop:
  316. for {
  317. // t will contain the match offset when we find one.
  318. // When existing the search loop, we have already checked 4 bytes.
  319. var t int32
  320. // We will not use repeat offsets across blocks.
  321. // By not using them for the first 3 matches
  322. for {
  323. nextHash := hashLen(cv, hashLog, tableFastHashLen)
  324. nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
  325. candidate := e.table[nextHash]
  326. candidate2 := e.table[nextHash2]
  327. repIndex := s - offset1 + 2
  328. e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
  329. e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
  330. if len(blk.sequences) > 2 && load3232(src, repIndex) == uint32(cv>>16) {
  331. // Consider history as well.
  332. var seq seq
  333. length := 4 + e.matchlen(s+6, repIndex+4, src)
  334. seq.matchLen = uint32(length - zstdMinMatch)
  335. // We might be able to match backwards.
  336. // Extend as long as we can.
  337. start := s + 2
  338. // We end the search early, so we don't risk 0 literals
  339. // and have to do special offset treatment.
  340. startLimit := nextEmit + 1
  341. sMin := s - e.maxMatchOff
  342. if sMin < 0 {
  343. sMin = 0
  344. }
  345. for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] {
  346. repIndex--
  347. start--
  348. seq.matchLen++
  349. }
  350. addLiterals(&seq, start)
  351. // rep 0
  352. seq.offset = 1
  353. if debugSequences {
  354. println("repeat sequence", seq, "next s:", s)
  355. }
  356. blk.sequences = append(blk.sequences, seq)
  357. s += length + 2
  358. nextEmit = s
  359. if s >= sLimit {
  360. if debugEncoder {
  361. println("repeat ended", s, length)
  362. }
  363. break encodeLoop
  364. }
  365. cv = load6432(src, s)
  366. continue
  367. }
  368. coffset0 := s - (candidate.offset - e.cur)
  369. coffset1 := s - (candidate2.offset - e.cur) + 1
  370. if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
  371. // found a regular match
  372. t = candidate.offset - e.cur
  373. if debugAsserts && s <= t {
  374. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  375. }
  376. if debugAsserts && s-t > e.maxMatchOff {
  377. panic("s - t >e.maxMatchOff")
  378. }
  379. if debugAsserts && t < 0 {
  380. panic(fmt.Sprintf("t (%d) < 0, candidate.offset: %d, e.cur: %d, coffset0: %d, e.maxMatchOff: %d", t, candidate.offset, e.cur, coffset0, e.maxMatchOff))
  381. }
  382. break
  383. }
  384. if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
  385. // found a regular match
  386. t = candidate2.offset - e.cur
  387. s++
  388. if debugAsserts && s <= t {
  389. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  390. }
  391. if debugAsserts && s-t > e.maxMatchOff {
  392. panic("s - t >e.maxMatchOff")
  393. }
  394. if debugAsserts && t < 0 {
  395. panic("t<0")
  396. }
  397. break
  398. }
  399. s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
  400. if s >= sLimit {
  401. break encodeLoop
  402. }
  403. cv = load6432(src, s)
  404. }
  405. // A 4-byte match has been found. We'll later see if more than 4 bytes.
  406. offset2 = offset1
  407. offset1 = s - t
  408. if debugAsserts && s <= t {
  409. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  410. }
  411. if debugAsserts && t < 0 {
  412. panic(fmt.Sprintf("t (%d) < 0 ", t))
  413. }
  414. // Extend the 4-byte match as long as possible.
  415. l := e.matchlen(s+4, t+4, src) + 4
  416. // Extend backwards
  417. tMin := s - e.maxMatchOff
  418. if tMin < 0 {
  419. tMin = 0
  420. }
  421. for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
  422. s--
  423. t--
  424. l++
  425. }
  426. // Write our sequence.
  427. var seq seq
  428. seq.litLen = uint32(s - nextEmit)
  429. seq.matchLen = uint32(l - zstdMinMatch)
  430. if seq.litLen > 0 {
  431. blk.literals = append(blk.literals, src[nextEmit:s]...)
  432. }
  433. // Don't use repeat offsets
  434. seq.offset = uint32(s-t) + 3
  435. s += l
  436. if debugSequences {
  437. println("sequence", seq, "next s:", s)
  438. }
  439. blk.sequences = append(blk.sequences, seq)
  440. nextEmit = s
  441. if s >= sLimit {
  442. break encodeLoop
  443. }
  444. cv = load6432(src, s)
  445. // Check offset 2
  446. if o2 := s - offset2; len(blk.sequences) > 2 && load3232(src, o2) == uint32(cv) {
  447. // We have at least 4 byte match.
  448. // No need to check backwards. We come straight from a match
  449. l := 4 + e.matchlen(s+4, o2+4, src)
  450. // Store this, since we have it.
  451. nextHash := hashLen(cv, hashLog, tableFastHashLen)
  452. e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
  453. seq.matchLen = uint32(l) - zstdMinMatch
  454. seq.litLen = 0
  455. // Since litlen is always 0, this is offset 1.
  456. seq.offset = 1
  457. s += l
  458. nextEmit = s
  459. if debugSequences {
  460. println("sequence", seq, "next s:", s)
  461. }
  462. blk.sequences = append(blk.sequences, seq)
  463. // Swap offset 1 and 2.
  464. offset1, offset2 = offset2, offset1
  465. if s >= sLimit {
  466. break encodeLoop
  467. }
  468. // Prepare next loop.
  469. cv = load6432(src, s)
  470. }
  471. }
  472. if int(nextEmit) < len(src) {
  473. blk.literals = append(blk.literals, src[nextEmit:]...)
  474. blk.extraLits = len(src) - int(nextEmit)
  475. }
  476. if debugEncoder {
  477. println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
  478. }
  479. // We do not store history, so we must offset e.cur to avoid false matches for next user.
  480. if e.cur < bufferReset {
  481. e.cur += int32(len(src))
  482. }
  483. }
  484. // Encode will encode the content, with a dictionary if initialized for it.
  485. func (e *fastEncoderDict) Encode(blk *blockEnc, src []byte) {
  486. const (
  487. inputMargin = 8
  488. minNonLiteralBlockSize = 1 + 1 + inputMargin
  489. )
  490. if e.allDirty || len(src) > 32<<10 {
  491. e.fastEncoder.Encode(blk, src)
  492. e.allDirty = true
  493. return
  494. }
  495. // Protect against e.cur wraparound.
  496. for e.cur >= bufferReset {
  497. if len(e.hist) == 0 {
  498. for i := range e.table[:] {
  499. e.table[i] = tableEntry{}
  500. }
  501. e.cur = e.maxMatchOff
  502. break
  503. }
  504. // Shift down everything in the table that isn't already too far away.
  505. minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
  506. for i := range e.table[:] {
  507. v := e.table[i].offset
  508. if v < minOff {
  509. v = 0
  510. } else {
  511. v = v - e.cur + e.maxMatchOff
  512. }
  513. e.table[i].offset = v
  514. }
  515. e.cur = e.maxMatchOff
  516. break
  517. }
  518. s := e.addBlock(src)
  519. blk.size = len(src)
  520. if len(src) < minNonLiteralBlockSize {
  521. blk.extraLits = len(src)
  522. blk.literals = blk.literals[:len(src)]
  523. copy(blk.literals, src)
  524. return
  525. }
  526. // Override src
  527. src = e.hist
  528. sLimit := int32(len(src)) - inputMargin
  529. // stepSize is the number of bytes to skip on every main loop iteration.
  530. // It should be >= 2.
  531. const stepSize = 2
  532. // TEMPLATE
  533. const hashLog = tableBits
  534. // seems global, but would be nice to tweak.
  535. const kSearchStrength = 7
  536. // nextEmit is where in src the next emitLiteral should start from.
  537. nextEmit := s
  538. cv := load6432(src, s)
  539. // Relative offsets
  540. offset1 := int32(blk.recentOffsets[0])
  541. offset2 := int32(blk.recentOffsets[1])
  542. addLiterals := func(s *seq, until int32) {
  543. if until == nextEmit {
  544. return
  545. }
  546. blk.literals = append(blk.literals, src[nextEmit:until]...)
  547. s.litLen = uint32(until - nextEmit)
  548. }
  549. if debugEncoder {
  550. println("recent offsets:", blk.recentOffsets)
  551. }
  552. encodeLoop:
  553. for {
  554. // t will contain the match offset when we find one.
  555. // When existing the search loop, we have already checked 4 bytes.
  556. var t int32
  557. // We will not use repeat offsets across blocks.
  558. // By not using them for the first 3 matches
  559. canRepeat := len(blk.sequences) > 2
  560. for {
  561. if debugAsserts && canRepeat && offset1 == 0 {
  562. panic("offset0 was 0")
  563. }
  564. nextHash := hashLen(cv, hashLog, tableFastHashLen)
  565. nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
  566. candidate := e.table[nextHash]
  567. candidate2 := e.table[nextHash2]
  568. repIndex := s - offset1 + 2
  569. e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
  570. e.markShardDirty(nextHash)
  571. e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
  572. e.markShardDirty(nextHash2)
  573. if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) {
  574. // Consider history as well.
  575. var seq seq
  576. var length int32
  577. length = 4 + e.matchlen(s+6, repIndex+4, src)
  578. seq.matchLen = uint32(length - zstdMinMatch)
  579. // We might be able to match backwards.
  580. // Extend as long as we can.
  581. start := s + 2
  582. // We end the search early, so we don't risk 0 literals
  583. // and have to do special offset treatment.
  584. startLimit := nextEmit + 1
  585. sMin := s - e.maxMatchOff
  586. if sMin < 0 {
  587. sMin = 0
  588. }
  589. for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
  590. repIndex--
  591. start--
  592. seq.matchLen++
  593. }
  594. addLiterals(&seq, start)
  595. // rep 0
  596. seq.offset = 1
  597. if debugSequences {
  598. println("repeat sequence", seq, "next s:", s)
  599. }
  600. blk.sequences = append(blk.sequences, seq)
  601. s += length + 2
  602. nextEmit = s
  603. if s >= sLimit {
  604. if debugEncoder {
  605. println("repeat ended", s, length)
  606. }
  607. break encodeLoop
  608. }
  609. cv = load6432(src, s)
  610. continue
  611. }
  612. coffset0 := s - (candidate.offset - e.cur)
  613. coffset1 := s - (candidate2.offset - e.cur) + 1
  614. if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
  615. // found a regular match
  616. t = candidate.offset - e.cur
  617. if debugAsserts && s <= t {
  618. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  619. }
  620. if debugAsserts && s-t > e.maxMatchOff {
  621. panic("s - t >e.maxMatchOff")
  622. }
  623. break
  624. }
  625. if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
  626. // found a regular match
  627. t = candidate2.offset - e.cur
  628. s++
  629. if debugAsserts && s <= t {
  630. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  631. }
  632. if debugAsserts && s-t > e.maxMatchOff {
  633. panic("s - t >e.maxMatchOff")
  634. }
  635. if debugAsserts && t < 0 {
  636. panic("t<0")
  637. }
  638. break
  639. }
  640. s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
  641. if s >= sLimit {
  642. break encodeLoop
  643. }
  644. cv = load6432(src, s)
  645. }
  646. // A 4-byte match has been found. We'll later see if more than 4 bytes.
  647. offset2 = offset1
  648. offset1 = s - t
  649. if debugAsserts && s <= t {
  650. panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
  651. }
  652. if debugAsserts && canRepeat && int(offset1) > len(src) {
  653. panic("invalid offset")
  654. }
  655. // Extend the 4-byte match as long as possible.
  656. l := e.matchlen(s+4, t+4, src) + 4
  657. // Extend backwards
  658. tMin := s - e.maxMatchOff
  659. if tMin < 0 {
  660. tMin = 0
  661. }
  662. for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
  663. s--
  664. t--
  665. l++
  666. }
  667. // Write our sequence.
  668. var seq seq
  669. seq.litLen = uint32(s - nextEmit)
  670. seq.matchLen = uint32(l - zstdMinMatch)
  671. if seq.litLen > 0 {
  672. blk.literals = append(blk.literals, src[nextEmit:s]...)
  673. }
  674. // Don't use repeat offsets
  675. seq.offset = uint32(s-t) + 3
  676. s += l
  677. if debugSequences {
  678. println("sequence", seq, "next s:", s)
  679. }
  680. blk.sequences = append(blk.sequences, seq)
  681. nextEmit = s
  682. if s >= sLimit {
  683. break encodeLoop
  684. }
  685. cv = load6432(src, s)
  686. // Check offset 2
  687. if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) {
  688. // We have at least 4 byte match.
  689. // No need to check backwards. We come straight from a match
  690. l := 4 + e.matchlen(s+4, o2+4, src)
  691. // Store this, since we have it.
  692. nextHash := hashLen(cv, hashLog, tableFastHashLen)
  693. e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
  694. e.markShardDirty(nextHash)
  695. seq.matchLen = uint32(l) - zstdMinMatch
  696. seq.litLen = 0
  697. // Since litlen is always 0, this is offset 1.
  698. seq.offset = 1
  699. s += l
  700. nextEmit = s
  701. if debugSequences {
  702. println("sequence", seq, "next s:", s)
  703. }
  704. blk.sequences = append(blk.sequences, seq)
  705. // Swap offset 1 and 2.
  706. offset1, offset2 = offset2, offset1
  707. if s >= sLimit {
  708. break encodeLoop
  709. }
  710. // Prepare next loop.
  711. cv = load6432(src, s)
  712. }
  713. }
  714. if int(nextEmit) < len(src) {
  715. blk.literals = append(blk.literals, src[nextEmit:]...)
  716. blk.extraLits = len(src) - int(nextEmit)
  717. }
  718. blk.recentOffsets[0] = uint32(offset1)
  719. blk.recentOffsets[1] = uint32(offset2)
  720. if debugEncoder {
  721. println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
  722. }
  723. }
  724. // ResetDict will reset and set a dictionary if not nil
  725. func (e *fastEncoder) Reset(d *dict, singleBlock bool) {
  726. e.resetBase(d, singleBlock)
  727. if d != nil {
  728. panic("fastEncoder: Reset with dict")
  729. }
  730. }
  731. // ResetDict will reset and set a dictionary if not nil
  732. func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) {
  733. e.resetBase(d, singleBlock)
  734. if d == nil {
  735. return
  736. }
  737. // Init or copy dict table
  738. if len(e.dictTable) != len(e.table) || d.id != e.lastDictID {
  739. if len(e.dictTable) != len(e.table) {
  740. e.dictTable = make([]tableEntry, len(e.table))
  741. }
  742. if true {
  743. end := e.maxMatchOff + int32(len(d.content)) - 8
  744. for i := e.maxMatchOff; i < end; i += 3 {
  745. const hashLog = tableBits
  746. cv := load6432(d.content, i-e.maxMatchOff)
  747. nextHash := hashLen(cv, hashLog, tableFastHashLen) // 0 -> 5
  748. nextHash1 := hashLen(cv>>8, hashLog, tableFastHashLen) // 1 -> 6
  749. nextHash2 := hashLen(cv>>16, hashLog, tableFastHashLen) // 2 -> 7
  750. e.dictTable[nextHash] = tableEntry{
  751. val: uint32(cv),
  752. offset: i,
  753. }
  754. e.dictTable[nextHash1] = tableEntry{
  755. val: uint32(cv >> 8),
  756. offset: i + 1,
  757. }
  758. e.dictTable[nextHash2] = tableEntry{
  759. val: uint32(cv >> 16),
  760. offset: i + 2,
  761. }
  762. }
  763. }
  764. e.lastDictID = d.id
  765. e.allDirty = true
  766. }
  767. e.cur = e.maxMatchOff
  768. dirtyShardCnt := 0
  769. if !e.allDirty {
  770. for i := range e.tableShardDirty {
  771. if e.tableShardDirty[i] {
  772. dirtyShardCnt++
  773. }
  774. }
  775. }
  776. const shardCnt = tableShardCnt
  777. const shardSize = tableShardSize
  778. if e.allDirty || dirtyShardCnt > shardCnt*4/6 {
  779. copy(e.table[:], e.dictTable)
  780. for i := range e.tableShardDirty {
  781. e.tableShardDirty[i] = false
  782. }
  783. e.allDirty = false
  784. return
  785. }
  786. for i := range e.tableShardDirty {
  787. if !e.tableShardDirty[i] {
  788. continue
  789. }
  790. copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize])
  791. e.tableShardDirty[i] = false
  792. }
  793. e.allDirty = false
  794. }
  795. func (e *fastEncoderDict) markAllShardsDirty() {
  796. e.allDirty = true
  797. }
  798. func (e *fastEncoderDict) markShardDirty(entryNum uint32) {
  799. e.tableShardDirty[entryNum/tableShardSize] = true
  800. }