| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 | 
							- package plumbing
 
- // Adapted from https://github.com/kr/binarydist
 
- // Original license:
 
- //
 
- // Copyright 2012 Keith Rarick
 
- //
 
- // Permission is hereby granted, free of charge, to any person
 
- // obtaining a copy of this software and associated documentation
 
- // files (the "Software"), to deal in the Software without
 
- // restriction, including without limitation the rights to use,
 
- // copy, modify, merge, publish, distribute, sublicense, and/or sell
 
- // copies of the Software, and to permit persons to whom the
 
- // Software is furnished to do so, subject to the following
 
- // conditions:
 
- //
 
- // The above copyright notice and this permission notice shall be
 
- // included in all copies or substantial portions of the Software.
 
- //
 
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
- // OTHER DEALINGS IN THE SOFTWARE.
 
- import (
 
- 	"bytes"
 
- )
 
- func swap(a []int, i, j int) { a[i], a[j] = a[j], a[i] }
 
- func split(I, V []int, start, length, h int) {
 
- 	var i, j, k, x, jj, kk int
 
- 	if length < 16 {
 
- 		for k = start; k < start+length; k += j {
 
- 			j = 1
 
- 			x = V[I[k]+h]
 
- 			for i = 1; k+i < start+length; i++ {
 
- 				if V[I[k+i]+h] < x {
 
- 					x = V[I[k+i]+h]
 
- 					j = 0
 
- 				}
 
- 				if V[I[k+i]+h] == x {
 
- 					swap(I, k+i, k+j)
 
- 					j++
 
- 				}
 
- 			}
 
- 			for i = 0; i < j; i++ {
 
- 				V[I[k+i]] = k + j - 1
 
- 			}
 
- 			if j == 1 {
 
- 				I[k] = -1
 
- 			}
 
- 		}
 
- 		return
 
- 	}
 
- 	x = V[I[start+length/2]+h]
 
- 	jj = 0
 
- 	kk = 0
 
- 	for i = start; i < start+length; i++ {
 
- 		if V[I[i]+h] < x {
 
- 			jj++
 
- 		}
 
- 		if V[I[i]+h] == x {
 
- 			kk++
 
- 		}
 
- 	}
 
- 	jj += start
 
- 	kk += jj
 
- 	i = start
 
- 	j = 0
 
- 	k = 0
 
- 	for i < jj {
 
- 		if V[I[i]+h] < x {
 
- 			i++
 
- 		} else if V[I[i]+h] == x {
 
- 			swap(I, i, jj+j)
 
- 			j++
 
- 		} else {
 
- 			swap(I, i, kk+k)
 
- 			k++
 
- 		}
 
- 	}
 
- 	for jj+j < kk {
 
- 		if V[I[jj+j]+h] == x {
 
- 			j++
 
- 		} else {
 
- 			swap(I, jj+j, kk+k)
 
- 			k++
 
- 		}
 
- 	}
 
- 	if jj > start {
 
- 		split(I, V, start, jj-start, h)
 
- 	}
 
- 	for i = 0; i < kk-jj; i++ {
 
- 		V[I[jj+i]] = kk - 1
 
- 	}
 
- 	if jj == kk-1 {
 
- 		I[jj] = -1
 
- 	}
 
- 	if start+length > kk {
 
- 		split(I, V, kk, start+length-kk, h)
 
- 	}
 
- }
 
- func qsufsort(obuf []byte) []int {
 
- 	var buckets [256]int
 
- 	var i, h int
 
- 	I := make([]int, len(obuf)+1)
 
- 	V := make([]int, len(obuf)+1)
 
- 	for _, c := range obuf {
 
- 		buckets[c]++
 
- 	}
 
- 	for i = 1; i < 256; i++ {
 
- 		buckets[i] += buckets[i-1]
 
- 	}
 
- 	copy(buckets[1:], buckets[:])
 
- 	buckets[0] = 0
 
- 	for i, c := range obuf {
 
- 		buckets[c]++
 
- 		I[buckets[c]] = i
 
- 	}
 
- 	I[0] = len(obuf)
 
- 	for i, c := range obuf {
 
- 		V[i] = buckets[c]
 
- 	}
 
- 	V[len(obuf)] = 0
 
- 	for i = 1; i < 256; i++ {
 
- 		if buckets[i] == buckets[i-1]+1 {
 
- 			I[buckets[i]] = -1
 
- 		}
 
- 	}
 
- 	I[0] = -1
 
- 	for h = 1; I[0] != -(len(obuf) + 1); h += h {
 
- 		var n int
 
- 		for i = 0; i < len(obuf)+1; {
 
- 			if I[i] < 0 {
 
- 				n -= I[i]
 
- 				i -= I[i]
 
- 			} else {
 
- 				if n != 0 {
 
- 					I[i-n] = -n
 
- 				}
 
- 				n = V[I[i]] + 1 - i
 
- 				split(I, V, i, n, h)
 
- 				i += n
 
- 				n = 0
 
- 			}
 
- 		}
 
- 		if n != 0 {
 
- 			I[i-n] = -n
 
- 		}
 
- 	}
 
- 	for i = 0; i < len(obuf)+1; i++ {
 
- 		I[V[i]] = i
 
- 	}
 
- 	return I
 
- }
 
- func matchlen(a, b []byte) (i int) {
 
- 	for i < len(a) && i < len(b) && a[i] == b[i] {
 
- 		i++
 
- 	}
 
- 	return i
 
- }
 
- func search(I []int, obuf, nbuf []byte, st, en int) (pos, n int) {
 
- 	if en-st < 2 {
 
- 		x := matchlen(obuf[I[st]:], nbuf)
 
- 		y := matchlen(obuf[I[en]:], nbuf)
 
- 		if x > y {
 
- 			return I[st], x
 
- 		}
 
- 		return I[en], y
 
- 	}
 
- 	x := st + (en-st)/2
 
- 	if bytes.Compare(obuf[I[x]:], nbuf) < 0 {
 
- 		return search(I, obuf, nbuf, x, en)
 
- 	}
 
- 	return search(I, obuf, nbuf, st, x)
 
- }
 
- // DiffBytes calculates the approximated number of different bytes between two binary buffers.
 
- // We are not interested in the diff script itself. Instead, we track the sizes of `db` and `eb`
 
- // from the original implementation.
 
- func DiffBytes(obuf, nbuf []byte) int {
 
- 	if len(nbuf) < len(obuf) {
 
- 		obuf, nbuf = nbuf, obuf
 
- 	}
 
- 	var lenf int
 
- 	I := qsufsort(obuf)
 
- 	var dblen, eblen int
 
- 	// Compute the differences, writing ctrl as we go
 
- 	var scan, pos, length int
 
- 	var lastscan, lastpos, lastoffset int
 
- 	for scan < len(nbuf) {
 
- 		var oldscore int
 
- 		scan += length
 
- 		for scsc := scan; scan < len(nbuf); scan++ {
 
- 			pos, length = search(I, obuf, nbuf[scan:], 0, len(obuf))
 
- 			for ; scsc < scan+length; scsc++ {
 
- 				if scsc+lastoffset < len(obuf) &&
 
- 					obuf[scsc+lastoffset] == nbuf[scsc] {
 
- 					oldscore++
 
- 				}
 
- 			}
 
- 			if (length == oldscore && length != 0) || length > oldscore+8 {
 
- 				break
 
- 			}
 
- 			if scan+lastoffset < len(obuf) && obuf[scan+lastoffset] == nbuf[scan] {
 
- 				oldscore--
 
- 			}
 
- 		}
 
- 		if length != oldscore || scan == len(nbuf) {
 
- 			var s, Sf int
 
- 			lenf = 0
 
- 			for i := 0; lastscan+i < scan && lastpos+i < len(obuf); {
 
- 				if obuf[lastpos+i] == nbuf[lastscan+i] {
 
- 					s++
 
- 				}
 
- 				i++
 
- 				if s*2-i > Sf*2-lenf {
 
- 					Sf = s
 
- 					lenf = i
 
- 				}
 
- 			}
 
- 			lenb := 0
 
- 			if scan < len(nbuf) {
 
- 				var s, Sb int
 
- 				for i := 1; (scan >= lastscan+i) && (pos >= i); i++ {
 
- 					if obuf[pos-i] == nbuf[scan-i] {
 
- 						s++
 
- 					}
 
- 					if s*2-i > Sb*2-lenb {
 
- 						Sb = s
 
- 						lenb = i
 
- 					}
 
- 				}
 
- 			}
 
- 			if lastscan+lenf > scan-lenb {
 
- 				overlap := (lastscan + lenf) - (scan - lenb)
 
- 				s := 0
 
- 				Ss := 0
 
- 				lens := 0
 
- 				for i := 0; i < overlap; i++ {
 
- 					if nbuf[lastscan+lenf-overlap+i] == obuf[lastpos+lenf-overlap+i] {
 
- 						s++
 
- 					}
 
- 					if nbuf[scan-lenb+i] == obuf[pos-lenb+i] {
 
- 						s--
 
- 					}
 
- 					if s > Ss {
 
- 						Ss = s
 
- 						lens = i + 1
 
- 					}
 
- 				}
 
- 				lenf += lens - overlap
 
- 				lenb -= lens
 
- 			}
 
- 			var nonzero int
 
- 			for i := 0; i < lenf; i++ {
 
- 				if nbuf[lastscan+i]-obuf[lastpos+i] != 0 {
 
- 					nonzero++
 
- 				}
 
- 			}
 
- 			dblen += nonzero
 
- 			eblen += (scan - lenb) - (lastscan + lenf)
 
- 			lastscan = scan - lenb
 
- 			lastpos = pos - lenb
 
- 			lastoffset = pos - scan
 
- 		}
 
- 	}
 
- 	return dblen + eblen
 
- }
 
 
  |