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 }