github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/rollsum/rollsum.go (about) 1 /* 2 Copyright 2011 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package rollsum implements rolling checksums similar to apenwarr's bup, which 18 // is similar to librsync. 19 // 20 // The bup project is at https://github.com/apenwarr/bup and its splitting in 21 // particular is at https://github.com/apenwarr/bup/blob/master/lib/bup/bupsplit.c 22 package rollsum 23 24 import () 25 26 const windowSize = 64 27 const charOffset = 31 28 29 const blobBits = 13 30 const blobSize = 1 << blobBits // 8k 31 32 type RollSum struct { 33 s1, s2 uint32 34 window [windowSize]uint8 35 wofs int 36 } 37 38 func New() *RollSum { 39 return &RollSum{ 40 s1: windowSize * charOffset, 41 s2: windowSize * (windowSize - 1) * charOffset, 42 } 43 } 44 45 func (rs *RollSum) add(drop, add uint8) { 46 rs.s1 += uint32(add) - uint32(drop) 47 rs.s2 += rs.s1 - uint32(windowSize)*uint32(drop+charOffset) 48 } 49 50 func (rs *RollSum) Roll(ch byte) { 51 rs.add(rs.window[rs.wofs], ch) 52 rs.window[rs.wofs] = ch 53 rs.wofs = (rs.wofs + 1) % windowSize 54 } 55 56 // OnSplit returns whether at least 13 consecutive trailing bits of 57 // the current checksum are set the same way. 58 func (rs *RollSum) OnSplit() bool { 59 return (rs.s2 & (blobSize - 1)) == ((^0) & (blobSize - 1)) 60 } 61 62 // OnSplit returns whether at least n consecutive trailing bits 63 // of the current checksum are set the same way. 64 func (rs *RollSum) OnSplitWithBits(n uint32) bool { 65 mask := (uint32(1) << n) - 1 66 return rs.s2&mask == (^uint32(0))&mask 67 } 68 69 func (rs *RollSum) Bits() int { 70 bits := blobBits 71 rsum := rs.Digest() 72 rsum >>= blobBits 73 for ; (rsum>>1)&1 != 0; bits++ { 74 rsum >>= 1 75 } 76 return bits 77 } 78 79 func (rs *RollSum) Digest() uint32 { 80 return (rs.s1 << 16) | (rs.s2 & 0xffff) 81 }