private static void modifyOffset ( final CpcSketch sketch , final int newOffset ) { assert ( ( newOffset >= 0 ) && ( newOffset <= 56 ) ) ; assert ( newOffset == ( sketch . windowOffset + 1 ) ) ; assert ( newOffset == CpcUtil . determineCorrectOffset ( sketch . lgK , sketch . numCoupons ) ) ; assert ( sketch . slidingWindow != null ) ; assert ( sketch . pairTable != null ) ; final int k = 1 << sketch . lgK ; // Construct the full-sized bit matrix that corresponds to the sketch final long [ ] bitMatrix = CpcUtil . bitMatrixOfSketch ( sketch ) ; // refresh the KXP register on every 8th window shift. if ( ( newOffset & 0x7 ) == 0 ) { refreshKXP ( sketch , bitMatrix ) ; } sketch . pairTable . clear ( ) ; final PairTable table = sketch . pairTable ; final byte [ ] window = sketch . slidingWindow ; final long maskForClearingWindow = ( 0XFF L << newOffset ) ^ - 1L ; final long maskForFlippingEarlyZone = ( 1L << newOffset ) - 1L ; long allSurprisesORed = 0 ; for ( int i = 0 ; i < k ; i ++ ) { long pattern = bitMatrix [ i ] ; window [ i ] = ( byte ) ( ( pattern >>> newOffset ) & 0XFF L ) ; pattern &= maskForClearingWindow ; // The following line converts surprising 0's to 1's in the "early zone", // (and vice versa, which is essential for this procedure's O(k) time cost). pattern ^= maskForFlippingEarlyZone ; allSurprisesORed |= pattern ; // a cheap way to recalculate fiCol while ( pattern != 0 ) { final int col = Long . numberOfTrailingZeros ( pattern ) ; pattern = pattern ^ ( 1L << col ) ; // erase the 1. final int rowCol = ( i << 6 ) | col ; final boolean isNovel = PairTable . maybeInsert ( table , rowCol ) ; assert isNovel == true ; } } sketch . windowOffset = newOffset ; sketch . fiCol = Long . numberOfTrailingZeros ( allSurprisesORed ) ; if ( sketch . fiCol > newOffset ) { sketch . fiCol = newOffset ; // corner case } }
This moves the sliding window