github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/snappy/encode.go (about) 1 // Copyright 2011 The Snappy-Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package snappy 6 7 import ( 8 "encoding/binary" 9 "errors" 10 "io" 11 ) 12 13 // maxOffset limits how far copy back-references can go, the same as the C++ 14 // code. 15 const maxOffset = 1 << 15 16 17 func load32(b []byte, i int) uint32 { 18 b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line. 19 return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 20 } 21 22 func load64(b []byte, i int) uint64 { 23 b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line. 24 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | 25 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 26 } 27 28 // emitLiteral writes a literal chunk and returns the number of bytes written. 29 func emitLiteral(dst, lit []byte) int { 30 i, n := 0, uint(len(lit)-1) 31 switch { 32 case n < 60: 33 dst[0] = uint8(n)<<2 | tagLiteral 34 i = 1 35 case n < 1<<8: 36 dst[0] = 60<<2 | tagLiteral 37 dst[1] = uint8(n) 38 i = 2 39 case n < 1<<16: 40 dst[0] = 61<<2 | tagLiteral 41 dst[1] = uint8(n) 42 dst[2] = uint8(n >> 8) 43 i = 3 44 case n < 1<<24: 45 dst[0] = 62<<2 | tagLiteral 46 dst[1] = uint8(n) 47 dst[2] = uint8(n >> 8) 48 dst[3] = uint8(n >> 16) 49 i = 4 50 case int64(n) < 1<<32: 51 dst[0] = 63<<2 | tagLiteral 52 dst[1] = uint8(n) 53 dst[2] = uint8(n >> 8) 54 dst[3] = uint8(n >> 16) 55 dst[4] = uint8(n >> 24) 56 i = 5 57 default: 58 panic("snappy: source buffer is too long") 59 } 60 if copy(dst[i:], lit) != len(lit) { 61 panic("snappy: destination buffer is too short") 62 } 63 return i + len(lit) 64 } 65 66 // emitCopy writes a copy chunk and returns the number of bytes written. 67 func emitCopy(dst []byte, offset, length int) int { 68 i := 0 69 // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The 70 // threshold for this loop is a little higher (at 68 = 64 + 4), and the 71 // length emitted down below is is a little lower (at 60 = 64 - 4), because 72 // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed 73 // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as 74 // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as 75 // 3+3 bytes). The magic 4 in the 64±4 is because the minimum length for a 76 // tagCopy1 op is 4 bytes, which is why a length 3 copy has to be an 77 // encodes-as-3-bytes tagCopy2 instead of an encodes-as-2-bytes tagCopy1. 78 for length >= 68 { 79 // Emit a length 64 copy, encoded as 3 bytes. 80 dst[i+0] = 63<<2 | tagCopy2 81 dst[i+1] = uint8(offset) 82 dst[i+2] = uint8(offset >> 8) 83 i += 3 84 length -= 64 85 } 86 if length > 64 { 87 // Emit a length 60 copy, encoded as 3 bytes. 88 dst[i+0] = 59<<2 | tagCopy2 89 dst[i+1] = uint8(offset) 90 dst[i+2] = uint8(offset >> 8) 91 i += 3 92 length -= 60 93 } 94 if length >= 12 || offset >= 2048 { 95 // Emit the remaining copy, encoded as 3 bytes. 96 dst[i+0] = uint8(length-1)<<2 | tagCopy2 97 dst[i+1] = uint8(offset) 98 dst[i+2] = uint8(offset >> 8) 99 return i + 3 100 } 101 // Emit the remaining copy, encoded as 2 bytes. 102 dst[i+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1 103 dst[i+1] = uint8(offset) 104 return i + 2 105 } 106 107 // Encode returns the encoded form of src. The returned slice may be a sub- 108 // slice of dst if dst was large enough to hold the entire encoded block. 109 // Otherwise, a newly allocated slice will be returned. 110 // 111 // It is valid to pass a nil dst. 112 func Encode(dst, src []byte) []byte { 113 if n := MaxEncodedLen(len(src)); n < 0 { 114 panic(ErrTooLarge) 115 } else if len(dst) < n { 116 dst = make([]byte, n) 117 } 118 119 // The block starts with the varint-encoded length of the decompressed bytes. 120 d := binary.PutUvarint(dst, uint64(len(src))) 121 122 for len(src) > 0 { 123 p := src 124 src = nil 125 if len(p) > maxBlockSize { 126 p, src = p[:maxBlockSize], p[maxBlockSize:] 127 } 128 if len(p) < minNonLiteralBlockSize { 129 d += emitLiteral(dst[d:], p) 130 } else { 131 d += encodeBlock(dst[d:], p) 132 } 133 } 134 return dst[:d] 135 } 136 137 // inputMargin is the minimum number of extra input bytes to keep, inside 138 // encodeBlock's inner loop. On some architectures, this margin lets us 139 // implement a fast path for emitLiteral, where the copy of short (<= 16 byte) 140 // literals can be implemented as a single load to and store from a 16-byte 141 // register. That literal's actual length can be as short as 1 byte, so this 142 // can copy up to 15 bytes too much, but that's OK as subsequent iterations of 143 // the encoding loop will fix up the copy overrun, and this inputMargin ensures 144 // that we don't overrun the dst and src buffers. 145 // 146 // TODO: implement this fast path. 147 const inputMargin = 16 - 1 148 149 // minNonLiteralBlockSize is the minimum size of the input to encodeBlock that 150 // could be encoded with a copy tag. This is the minimum with respect to the 151 // algorithm used by encodeBlock, not a minimum enforced by the file format. 152 // 153 // The encoded output must start with at least a 1 byte literal, as there are 154 // no previous bytes to copy. A minimal (1 byte) copy after that, generated 155 // from an emitCopy call in encodeBlock's main loop, would require at least 156 // another inputMargin bytes, for the reason above: we want any emitLiteral 157 // calls inside encodeBlock's main loop to use the fast path if possible, which 158 // requires being able to overrun by inputMargin bytes. Thus, 159 // minNonLiteralBlockSize equals 1 + 1 + inputMargin. 160 // 161 // The C++ code doesn't use this exact threshold, but it could, as discussed at 162 // https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion 163 // The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an 164 // optimization. It should not affect the encoded form. This is tested by 165 // TestSameEncodingAsCppShortCopies. 166 const minNonLiteralBlockSize = 1 + 1 + inputMargin 167 168 func hash(u, shift uint32) uint32 { 169 return (u * 0x1e35a7bd) >> shift 170 } 171 172 // encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It 173 // assumes that the varint-encoded length of the decompressed bytes has already 174 // been written. 175 // 176 // It also assumes that: 177 // len(dst) >= MaxEncodedLen(len(src)) && 178 // minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize 179 func encodeBlock(dst, src []byte) (d int) { 180 // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive. 181 // The table element type is uint16, as s < sLimit and sLimit < len(src) 182 // and len(src) <= maxBlockSize and maxBlockSize == 65536. 183 const ( 184 maxTableSize = 1 << 14 185 // tableMask is redundant, but helps the compiler eliminate bounds 186 // checks. 187 tableMask = maxTableSize - 1 188 ) 189 shift, tableSize := uint32(32-8), 1<<8 190 for tableSize < maxTableSize && tableSize < len(src) { 191 shift-- 192 tableSize *= 2 193 } 194 var table [maxTableSize]uint16 195 196 // sLimit is when to stop looking for offset/length copies. The inputMargin 197 // lets us use a fast path for emitLiteral in the main loop, while we are 198 // looking for copies. 199 sLimit := len(src) - inputMargin 200 201 // nextEmit is where in src the next emitLiteral should start from. 202 nextEmit := 0 203 204 // The encoded form must start with a literal, as there are no previous 205 // bytes to copy, so we start looking for hash matches at s == 1. 206 s := 1 207 nextHash := hash(load32(src, s), shift) 208 209 for { 210 // Copied from the C++ snappy implementation: 211 // 212 // Heuristic match skipping: If 32 bytes are scanned with no matches 213 // found, start looking only at every other byte. If 32 more bytes are 214 // scanned (or skipped), look at every third byte, etc.. When a match 215 // is found, immediately go back to looking at every byte. This is a 216 // small loss (~5% performance, ~0.1% density) for compressible data 217 // due to more bookkeeping, but for non-compressible data (such as 218 // JPEG) it's a huge win since the compressor quickly "realizes" the 219 // data is incompressible and doesn't bother looking for matches 220 // everywhere. 221 // 222 // The "skip" variable keeps track of how many bytes there are since 223 // the last match; dividing it by 32 (ie. right-shifting by five) gives 224 // the number of bytes to move ahead for each iteration. 225 skip := 32 226 227 nextS := s 228 candidate := 0 229 for { 230 s = nextS 231 bytesBetweenHashLookups := skip >> 5 232 nextS = s + bytesBetweenHashLookups 233 skip += bytesBetweenHashLookups 234 if nextS > sLimit { 235 goto emitRemainder 236 } 237 candidate = int(table[nextHash&tableMask]) 238 table[nextHash&tableMask] = uint16(s) 239 nextHash = hash(load32(src, nextS), shift) 240 if load32(src, s) == load32(src, candidate) { 241 break 242 } 243 } 244 245 // A 4-byte match has been found. We'll later see if more than 4 bytes 246 // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit 247 // them as literal bytes. 248 d += emitLiteral(dst[d:], src[nextEmit:s]) 249 250 // Call emitCopy, and then see if another emitCopy could be our next 251 // move. Repeat until we find no match for the input immediately after 252 // what was consumed by the last emitCopy call. 253 // 254 // If we exit this loop normally then we need to call emitLiteral next, 255 // though we don't yet know how big the literal will be. We handle that 256 // by proceeding to the next iteration of the main loop. We also can 257 // exit this loop via goto if we get close to exhausting the input. 258 for { 259 // Invariant: we have a 4-byte match at s, and no need to emit any 260 // literal bytes prior to s. 261 base := s 262 s += 4 263 for i := candidate + 4; s < len(src) && src[i] == src[s]; i, s = i+1, s+1 { 264 } 265 d += emitCopy(dst[d:], base-candidate, s-base) 266 nextEmit = s 267 if s >= sLimit { 268 goto emitRemainder 269 } 270 271 // We could immediately start working at s now, but to improve 272 // compression we first update the hash table at s-1 and at s. If 273 // another emitCopy is not our next move, also calculate nextHash 274 // at s+1. At least on GOARCH=amd64, these three hash calculations 275 // are faster as one load64 call (with some shifts) instead of 276 // three load32 calls. 277 x := load64(src, s-1) 278 prevHash := hash(uint32(x>>0), shift) 279 table[prevHash&tableMask] = uint16(s - 1) 280 currHash := hash(uint32(x>>8), shift) 281 candidate = int(table[currHash&tableMask]) 282 table[currHash&tableMask] = uint16(s) 283 if uint32(x>>8) != load32(src, candidate) { 284 nextHash = hash(uint32(x>>16), shift) 285 s++ 286 break 287 } 288 } 289 } 290 291 emitRemainder: 292 if nextEmit < len(src) { 293 d += emitLiteral(dst[d:], src[nextEmit:]) 294 } 295 return d 296 } 297 298 // MaxEncodedLen returns the maximum length of a snappy block, given its 299 // uncompressed length. 300 // 301 // It will return a negative value if srcLen is too large to encode. 302 func MaxEncodedLen(srcLen int) int { 303 n := uint64(srcLen) 304 if n > 0xffffffff { 305 return -1 306 } 307 // Compressed data can be defined as: 308 // compressed := item* literal* 309 // item := literal* copy 310 // 311 // The trailing literal sequence has a space blowup of at most 62/60 312 // since a literal of length 60 needs one tag byte + one extra byte 313 // for length information. 314 // 315 // Item blowup is trickier to measure. Suppose the "copy" op copies 316 // 4 bytes of data. Because of a special check in the encoding code, 317 // we produce a 4-byte copy only if the offset is < 65536. Therefore 318 // the copy op takes 3 bytes to encode, and this type of item leads 319 // to at most the 62/60 blowup for representing literals. 320 // 321 // Suppose the "copy" op copies 5 bytes of data. If the offset is big 322 // enough, it will take 5 bytes to encode the copy op. Therefore the 323 // worst case here is a one-byte literal followed by a five-byte copy. 324 // That is, 6 bytes of input turn into 7 bytes of "compressed" data. 325 // 326 // This last factor dominates the blowup, so the final estimate is: 327 n = 32 + n + n/6 328 if n > 0xffffffff { 329 return -1 330 } 331 return int(n) 332 } 333 334 var errClosed = errors.New("snappy: Writer is closed") 335 336 // NewWriter returns a new Writer that compresses to w. 337 // 338 // The Writer returned does not buffer writes. There is no need to Flush or 339 // Close such a Writer. 340 // 341 // Deprecated: the Writer returned is not suitable for many small writes, only 342 // for few large writes. Use NewBufferedWriter instead, which is efficient 343 // regardless of the frequency and shape of the writes, and remember to Close 344 // that Writer when done. 345 func NewWriter(w io.Writer) *Writer { 346 return &Writer{ 347 w: w, 348 obuf: make([]byte, obufLen), 349 } 350 } 351 352 // NewBufferedWriter returns a new Writer that compresses to w, using the 353 // framing format described at 354 // https://yougam/libraries/google/snappy/blob/master/framing_format.txt 355 // 356 // The Writer returned buffers writes. Users must call Close to guarantee all 357 // data has been forwarded to the underlying io.Writer. They may also call 358 // Flush zero or more times before calling Close. 359 func NewBufferedWriter(w io.Writer) *Writer { 360 return &Writer{ 361 w: w, 362 ibuf: make([]byte, 0, maxBlockSize), 363 obuf: make([]byte, obufLen), 364 } 365 } 366 367 // Writer is an io.Writer than can write Snappy-compressed bytes. 368 type Writer struct { 369 w io.Writer 370 err error 371 372 // ibuf is a buffer for the incoming (uncompressed) bytes. 373 // 374 // Its use is optional. For backwards compatibility, Writers created by the 375 // NewWriter function have ibuf == nil, do not buffer incoming bytes, and 376 // therefore do not need to be Flush'ed or Close'd. 377 ibuf []byte 378 379 // obuf is a buffer for the outgoing (compressed) bytes. 380 obuf []byte 381 382 // wroteStreamHeader is whether we have written the stream header. 383 wroteStreamHeader bool 384 } 385 386 // Reset discards the writer's state and switches the Snappy writer to write to 387 // w. This permits reusing a Writer rather than allocating a new one. 388 func (w *Writer) Reset(writer io.Writer) { 389 w.w = writer 390 w.err = nil 391 if w.ibuf != nil { 392 w.ibuf = w.ibuf[:0] 393 } 394 w.wroteStreamHeader = false 395 } 396 397 // Write satisfies the io.Writer interface. 398 func (w *Writer) Write(p []byte) (nRet int, errRet error) { 399 if w.ibuf == nil { 400 // Do not buffer incoming bytes. This does not perform or compress well 401 // if the caller of Writer.Write writes many small slices. This 402 // behavior is therefore deprecated, but still supported for backwards 403 // compatibility with code that doesn't explicitly Flush or Close. 404 return w.write(p) 405 } 406 407 // The remainder of this method is based on bufio.Writer.Write from the 408 // standard library. 409 410 for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil { 411 var n int 412 if len(w.ibuf) == 0 { 413 // Large write, empty buffer. 414 // Write directly from p to avoid copy. 415 n, _ = w.write(p) 416 } else { 417 n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) 418 w.ibuf = w.ibuf[:len(w.ibuf)+n] 419 w.Flush() 420 } 421 nRet += n 422 p = p[n:] 423 } 424 if w.err != nil { 425 return nRet, w.err 426 } 427 n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) 428 w.ibuf = w.ibuf[:len(w.ibuf)+n] 429 nRet += n 430 return nRet, nil 431 } 432 433 func (w *Writer) write(p []byte) (nRet int, errRet error) { 434 if w.err != nil { 435 return 0, w.err 436 } 437 for len(p) > 0 { 438 obufStart := len(magicChunk) 439 if !w.wroteStreamHeader { 440 w.wroteStreamHeader = true 441 copy(w.obuf, magicChunk) 442 obufStart = 0 443 } 444 445 var uncompressed []byte 446 if len(p) > maxBlockSize { 447 uncompressed, p = p[:maxBlockSize], p[maxBlockSize:] 448 } else { 449 uncompressed, p = p, nil 450 } 451 checksum := crc(uncompressed) 452 453 // Compress the buffer, discarding the result if the improvement 454 // isn't at least 12.5%. 455 compressed := Encode(w.obuf[obufHeaderLen:], uncompressed) 456 chunkType := uint8(chunkTypeCompressedData) 457 chunkLen := 4 + len(compressed) 458 obufEnd := obufHeaderLen + len(compressed) 459 if len(compressed) >= len(uncompressed)-len(uncompressed)/8 { 460 chunkType = chunkTypeUncompressedData 461 chunkLen = 4 + len(uncompressed) 462 obufEnd = obufHeaderLen 463 } 464 465 // Fill in the per-chunk header that comes before the body. 466 w.obuf[len(magicChunk)+0] = chunkType 467 w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0) 468 w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8) 469 w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16) 470 w.obuf[len(magicChunk)+4] = uint8(checksum >> 0) 471 w.obuf[len(magicChunk)+5] = uint8(checksum >> 8) 472 w.obuf[len(magicChunk)+6] = uint8(checksum >> 16) 473 w.obuf[len(magicChunk)+7] = uint8(checksum >> 24) 474 475 if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil { 476 w.err = err 477 return nRet, err 478 } 479 if chunkType == chunkTypeUncompressedData { 480 if _, err := w.w.Write(uncompressed); err != nil { 481 w.err = err 482 return nRet, err 483 } 484 } 485 nRet += len(uncompressed) 486 } 487 return nRet, nil 488 } 489 490 // Flush flushes the Writer to its underlying io.Writer. 491 func (w *Writer) Flush() error { 492 if w.err != nil { 493 return w.err 494 } 495 if len(w.ibuf) == 0 { 496 return nil 497 } 498 w.write(w.ibuf) 499 w.ibuf = w.ibuf[:0] 500 return w.err 501 } 502 503 // Close calls Flush and then closes the Writer. 504 func (w *Writer) Close() error { 505 w.Flush() 506 ret := w.err 507 if w.err == nil { 508 w.err = errClosed 509 } 510 return ret 511 }