Compare commits
No commits in common. "72c18ebad3c6c5f943a7bc0913970c0e337480f2" and "33ff96e45f00794f5b78baf500687dc5cc4a141c" have entirely different histories.
72c18ebad3
...
33ff96e45f
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
|||||||
module gitea.narnian.us/lordwelch/goimagehash
|
module gitea.narnian.us/lordwelch/goimagehash
|
||||||
|
|
||||||
go 1.22
|
go 1.21
|
||||||
|
|
||||||
toolchain go1.22.0
|
toolchain go1.22.0
|
||||||
|
|
||||||
|
@ -8,21 +8,28 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"gitea.narnian.us/lordwelch/goimagehash/etcs"
|
"gitea.narnian.us/lordwelch/goimagehash/etcs"
|
||||||
"gitea.narnian.us/lordwelch/goimagehash/pool"
|
|
||||||
"gitea.narnian.us/lordwelch/goimagehash/transforms"
|
"gitea.narnian.us/lordwelch/goimagehash/transforms"
|
||||||
"github.com/disintegration/imaging"
|
"github.com/disintegration/imaging"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bufPool = &pool.Pool{}
|
var bufPool = sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
// The Pool's New function should generally only return pointer
|
||||||
|
// types, since a pointer can be put into the return interface
|
||||||
|
// value without an allocation:
|
||||||
|
return &[]uint8{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func getBuf(size, capacity int) []uint8 {
|
func getBuf(size, capacity int) []uint8 {
|
||||||
if capacity < size {
|
if capacity < size {
|
||||||
capacity = size
|
capacity = size
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := *bufPool.Get()
|
buf := *bufPool.Get().(*[]uint8)
|
||||||
if cap(buf) < capacity {
|
if cap(buf) < capacity {
|
||||||
buf = make([]uint8, capacity)
|
buf = make([]uint8, capacity)
|
||||||
}
|
}
|
||||||
|
@ -19,33 +19,33 @@ func TestHashCompute(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
distance int
|
distance int
|
||||||
}{
|
}{
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", AverageHash, "AverageHash", 0},
|
{"_examples/sample1.jpg", "_examples/sample1.jpg", AverageHash, "AverageHash", 0},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", AverageHash, "AverageHash", 0},
|
{"_examples/sample2.jpg", "_examples/sample2.jpg", AverageHash, "AverageHash", 0},
|
||||||
{"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", AverageHash, "AverageHash", 0},
|
{"_examples/sample3.jpg", "_examples/sample3.jpg", AverageHash, "AverageHash", 0},
|
||||||
{"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", AverageHash, "AverageHash", 0},
|
{"_examples/sample4.jpg", "_examples/sample4.jpg", AverageHash, "AverageHash", 0},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", AverageHash, "AverageHash", 40},
|
{"_examples/sample1.jpg", "_examples/sample2.jpg", AverageHash, "AverageHash", 40},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", AverageHash, "AverageHash", 0},
|
{"_examples/sample1.jpg", "_examples/sample3.jpg", AverageHash, "AverageHash", 0},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", AverageHash, "AverageHash", 34},
|
{"_examples/sample1.jpg", "_examples/sample4.jpg", AverageHash, "AverageHash", 34},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", AverageHash, "AverageHash", 40},
|
{"_examples/sample2.jpg", "_examples/sample3.jpg", AverageHash, "AverageHash", 40},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", AverageHash, "AverageHash", 6},
|
{"_examples/sample2.jpg", "_examples/sample4.jpg", AverageHash, "AverageHash", 6},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", DifferenceHash, "DifferenceHash", 0},
|
{"_examples/sample1.jpg", "_examples/sample1.jpg", DifferenceHash, "DifferenceHash", 0},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", DifferenceHash, "DifferenceHash", 0},
|
{"_examples/sample2.jpg", "_examples/sample2.jpg", DifferenceHash, "DifferenceHash", 0},
|
||||||
{"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", DifferenceHash, "DifferenceHash", 0},
|
{"_examples/sample3.jpg", "_examples/sample3.jpg", DifferenceHash, "DifferenceHash", 0},
|
||||||
{"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", DifferenceHash, "DifferenceHash", 0},
|
{"_examples/sample4.jpg", "_examples/sample4.jpg", DifferenceHash, "DifferenceHash", 0},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", DifferenceHash, "DifferenceHash", 40},
|
{"_examples/sample1.jpg", "_examples/sample2.jpg", DifferenceHash, "DifferenceHash", 40},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", DifferenceHash, "DifferenceHash", 2},
|
{"_examples/sample1.jpg", "_examples/sample3.jpg", DifferenceHash, "DifferenceHash", 2},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", DifferenceHash, "DifferenceHash", 38},
|
{"_examples/sample1.jpg", "_examples/sample4.jpg", DifferenceHash, "DifferenceHash", 38},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", DifferenceHash, "DifferenceHash", 42},
|
{"_examples/sample2.jpg", "_examples/sample3.jpg", DifferenceHash, "DifferenceHash", 42},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", DifferenceHash, "DifferenceHash", 20},
|
{"_examples/sample2.jpg", "_examples/sample4.jpg", DifferenceHash, "DifferenceHash", 20},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", PerceptionHash, "PerceptionHash", 0},
|
{"_examples/sample1.jpg", "_examples/sample1.jpg", PerceptionHash, "PerceptionHash", 0},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", PerceptionHash, "PerceptionHash", 0},
|
{"_examples/sample2.jpg", "_examples/sample2.jpg", PerceptionHash, "PerceptionHash", 0},
|
||||||
{"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", PerceptionHash, "PerceptionHash", 0},
|
{"_examples/sample3.jpg", "_examples/sample3.jpg", PerceptionHash, "PerceptionHash", 0},
|
||||||
{"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", PerceptionHash, "PerceptionHash", 0},
|
{"_examples/sample4.jpg", "_examples/sample4.jpg", PerceptionHash, "PerceptionHash", 0},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", PerceptionHash, "PerceptionHash", 34},
|
{"_examples/sample1.jpg", "_examples/sample2.jpg", PerceptionHash, "PerceptionHash", 34},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", PerceptionHash, "PerceptionHash", 0},
|
{"_examples/sample1.jpg", "_examples/sample3.jpg", PerceptionHash, "PerceptionHash", 0},
|
||||||
{"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", PerceptionHash, "PerceptionHash", 30},
|
{"_examples/sample1.jpg", "_examples/sample4.jpg", PerceptionHash, "PerceptionHash", 30},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", PerceptionHash, "PerceptionHash", 34},
|
{"_examples/sample2.jpg", "_examples/sample3.jpg", PerceptionHash, "PerceptionHash", 34},
|
||||||
{"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", PerceptionHash, "PerceptionHash", 20},
|
{"_examples/sample2.jpg", "_examples/sample4.jpg", PerceptionHash, "PerceptionHash", 20},
|
||||||
} {
|
} {
|
||||||
file1, err := os.Open(tt.img1)
|
file1, err := os.Open(tt.img1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -124,7 +124,7 @@ func TestNilHashCompute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtendHashCompute(t *testing.T) {
|
func TestExtendHashCompute(t *testing.T) {
|
||||||
file, err := os.Open("_examples/images/sample1.jpg")
|
file, err := os.Open("_examples/sample1.jpg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s", err)
|
t.Errorf("%s", err)
|
||||||
}
|
}
|
||||||
@ -213,68 +213,68 @@ func BenchmarkDistanceDifferent(b *testing.B) {
|
|||||||
// name string
|
// name string
|
||||||
// distance int
|
// distance int
|
||||||
// }{
|
// }{
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 40},
|
// {"_examples/sample1.jpg", "_examples/sample2.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 40},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample3.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 34},
|
// {"_examples/sample1.jpg", "_examples/sample4.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 34},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 40},
|
// {"_examples/sample2.jpg", "_examples/sample3.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 40},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 6},
|
// {"_examples/sample2.jpg", "_examples/sample4.jpg", 8, 8, ExtAverageHash, "ExtAverageHash", 6},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 143},
|
// {"_examples/sample1.jpg", "_examples/sample2.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 143},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 3},
|
// {"_examples/sample1.jpg", "_examples/sample3.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 3},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 148},
|
// {"_examples/sample1.jpg", "_examples/sample4.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 148},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 146},
|
// {"_examples/sample2.jpg", "_examples/sample3.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 146},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 31},
|
// {"_examples/sample2.jpg", "_examples/sample4.jpg", 16, 16, ExtAverageHash, "ExtAverageHash", 31},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 17, 17, ExtAverageHash, "ExtAverageHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 32},
|
// {"_examples/sample1.jpg", "_examples/sample2.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 32},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 2},
|
// {"_examples/sample1.jpg", "_examples/sample3.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 2},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 30},
|
// {"_examples/sample1.jpg", "_examples/sample4.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 30},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 34},
|
// {"_examples/sample2.jpg", "_examples/sample3.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 34},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 20},
|
// {"_examples/sample2.jpg", "_examples/sample4.jpg", 8, 4, ExtPerceptionHash, "ExtPerceptionHash", 20},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 124},
|
// {"_examples/sample1.jpg", "_examples/sample2.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 124},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 14},
|
// {"_examples/sample1.jpg", "_examples/sample3.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 14},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 122},
|
// {"_examples/sample1.jpg", "_examples/sample4.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 122},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 120},
|
// {"_examples/sample2.jpg", "_examples/sample3.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 120},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 102},
|
// {"_examples/sample2.jpg", "_examples/sample4.jpg", 16, 4, ExtPerceptionHash, "ExtPerceptionHash", 102},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 40},
|
// {"_examples/sample1.jpg", "_examples/sample2.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 40},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 2},
|
// {"_examples/sample1.jpg", "_examples/sample3.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 2},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 38},
|
// {"_examples/sample1.jpg", "_examples/sample4.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 38},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 42},
|
// {"_examples/sample2.jpg", "_examples/sample3.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 42},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 20},
|
// {"_examples/sample2.jpg", "_examples/sample4.jpg", 8, 8, ExtDifferenceHash, "ExtDifferenceHash", 20},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 137},
|
// {"_examples/sample1.jpg", "_examples/sample2.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 137},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample3.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 13},
|
// {"_examples/sample1.jpg", "_examples/sample3.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 13},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample4.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 124},
|
// {"_examples/sample1.jpg", "_examples/sample4.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 124},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample3.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 140},
|
// {"_examples/sample2.jpg", "_examples/sample3.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 140},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample4.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 109},
|
// {"_examples/sample2.jpg", "_examples/sample4.jpg", 16, 16, ExtDifferenceHash, "ExtDifferenceHash", 109},
|
||||||
// {"_examples/images/sample1.jpg", "_examples/images/sample1.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample1.jpg", "_examples/sample1.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample2.jpg", "_examples/images/sample2.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample2.jpg", "_examples/sample2.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample3.jpg", "_examples/images/sample3.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample3.jpg", "_examples/sample3.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// {"_examples/images/sample4.jpg", "_examples/images/sample4.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
// {"_examples/sample4.jpg", "_examples/sample4.jpg", 17, 17, ExtDifferenceHash, "ExtDifferenceHash", 0},
|
||||||
// } {
|
// } {
|
||||||
// file1, err := os.Open(tt.img1)
|
// file1, err := os.Open(tt.img1)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
@ -340,7 +340,7 @@ func BenchmarkExtImageHashDistanceDifferent(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkPerceptionHash(b *testing.B) {
|
func BenchmarkPerceptionHash(b *testing.B) {
|
||||||
file1, err := os.Open("_examples/images/sample3.jpg")
|
file1, err := os.Open("_examples/sample3.jpg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Errorf("%s", err)
|
b.Errorf("%s", err)
|
||||||
}
|
}
|
||||||
@ -350,84 +350,45 @@ func BenchmarkPerceptionHash(b *testing.B) {
|
|||||||
b.Errorf("%s", err)
|
b.Errorf("%s", err)
|
||||||
}
|
}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := PerceptionHash(img1)
|
_, err := ExtPerceptionHash(img1, 8, 8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Errorf("%s", err)
|
b.Errorf("%s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkAverageHash(b *testing.B) {
|
// func BenchmarkAverageHash(b *testing.B) {
|
||||||
file1, err := os.Open("_examples/images/sample3.jpg")
|
// file1, err := os.Open("_examples/sample3.jpg")
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
b.Errorf("%s", err)
|
// b.Errorf("%s", err)
|
||||||
}
|
// }
|
||||||
defer file1.Close()
|
// defer file1.Close()
|
||||||
img1, err := jpeg.Decode(file1)
|
// img1, err := jpeg.Decode(file1)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
b.Errorf("%s", err)
|
// b.Errorf("%s", err)
|
||||||
}
|
// }
|
||||||
for i := 0; i < b.N; i++ {
|
// for i := 0; i < b.N; i++ {
|
||||||
_, err := AverageHash(img1)
|
// _, err := ExtAverageHash(img1, 8, 8)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
b.Errorf("%s", err)
|
// b.Errorf("%s", err)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func BenchmarkDifferenceHash(b *testing.B) {
|
// func BenchmarkDifferenceHash(b *testing.B) {
|
||||||
file1, err := os.Open("_examples/images/sample3.jpg")
|
// file1, err := os.Open("_examples/sample3.jpg")
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
b.Errorf("%s", err)
|
// b.Errorf("%s", err)
|
||||||
}
|
// }
|
||||||
defer file1.Close()
|
// defer file1.Close()
|
||||||
img1, err := jpeg.Decode(file1)
|
// img1, err := jpeg.Decode(file1)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
b.Errorf("%s", err)
|
// b.Errorf("%s", err)
|
||||||
}
|
// }
|
||||||
for i := 0; i < b.N; i++ {
|
// for i := 0; i < b.N; i++ {
|
||||||
_, err := DifferenceHash(img1)
|
// _, err := ExtDifferenceHash(img1, 8, 8)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
b.Errorf("%s", err)
|
// b.Errorf("%s", err)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func BenchmarkAllHash(b *testing.B) {
|
|
||||||
imagePaths := []string{
|
|
||||||
"_examples/images/example.png",
|
|
||||||
"_examples/images/sample1.jpg",
|
|
||||||
"_examples/images/sample2.jpg",
|
|
||||||
"_examples/images/sample3.jpg",
|
|
||||||
"_examples/images/sample4.jpg",
|
|
||||||
}
|
|
||||||
images := []image.Image{}
|
|
||||||
for _, path := range imagePaths {
|
|
||||||
file1, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
b.Errorf("%s", err)
|
|
||||||
}
|
|
||||||
defer file1.Close()
|
|
||||||
img, _, err := image.Decode(file1)
|
|
||||||
if err != nil {
|
|
||||||
b.Errorf("%s", err)
|
|
||||||
}
|
|
||||||
images = append(images, img)
|
|
||||||
}
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
for _, image := range images {
|
|
||||||
_, err := AverageHash(image)
|
|
||||||
if err != nil {
|
|
||||||
b.Errorf("%s", err)
|
|
||||||
}
|
|
||||||
_, err = DifferenceHash(image)
|
|
||||||
if err != nil {
|
|
||||||
b.Errorf("%s", err)
|
|
||||||
}
|
|
||||||
_, err = PerceptionHash(image)
|
|
||||||
if err != nil {
|
|
||||||
b.Errorf("%s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
_ "image/jpeg"
|
_ "image/jpeg"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ func TestNewImageHash(t *testing.T) {
|
|||||||
{[][]uint8{{1, 0, 1, 1}, {0, 0, 0, 0}}, Unknown, Unknown, 3, nil},
|
{[][]uint8{{1, 0, 1, 1}, {0, 0, 0, 0}}, Unknown, Unknown, 3, nil},
|
||||||
{[][]uint8{{0, 0, 0, 0}, {0, 0, 0, 0}}, Unknown, Unknown, 0, nil},
|
{[][]uint8{{0, 0, 0, 0}, {0, 0, 0, 0}}, Unknown, Unknown, 0, nil},
|
||||||
{[][]uint8{{0, 0, 0, 0}, {0, 0, 0, 1}}, Unknown, Unknown, 1, nil},
|
{[][]uint8{{0, 0, 0, 0}, {0, 0, 0, 1}}, Unknown, Unknown, 1, nil},
|
||||||
{[][]uint8{{0, 0, 0, 0}, {0, 0, 0, 1}}, Unknown, AHash, -1, errors.New("image hashes's kind should be identical")},
|
{[][]uint8{{0, 0, 0, 0}, {0, 0, 0, 1}}, Unknown, AHash, -1, errors.New("Image hashes's kind should be identical")},
|
||||||
} {
|
} {
|
||||||
data1 := tt.datas[0]
|
data1 := tt.datas[0]
|
||||||
data2 := tt.datas[1]
|
data2 := tt.datas[1]
|
||||||
@ -49,7 +51,7 @@ func TestNewImageHash(t *testing.T) {
|
|||||||
t.Errorf("Distance between %v and %v expected as %d but got %d", data1, data2, tt.distance, dis)
|
t.Errorf("Distance between %v and %v expected as %d but got %d", data1, data2, tt.distance, dis)
|
||||||
}
|
}
|
||||||
if err != nil && err.Error() != tt.err.Error() {
|
if err != nil && err.Error() != tt.err.Error() {
|
||||||
t.Errorf("Expected err %#v, actual %#v", tt.err, err)
|
t.Errorf("Expected err %s, actual %s", tt.err, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,13 +67,109 @@ func TestNil(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSerialization(t *testing.T) {
|
||||||
|
checkErr := func(err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
methods := []func(img image.Image) (*ImageHash, error){
|
||||||
|
AverageHash, PerceptionHash, DifferenceHash,
|
||||||
|
}
|
||||||
|
extMethods := []func(img image.Image, width int, height int) (*ExtImageHash, error){
|
||||||
|
// ExtAverageHash ExtPerceptionHash, , ExtDifferenceHash,
|
||||||
|
}
|
||||||
|
examples := []string{
|
||||||
|
"_examples/sample1.jpg", "_examples/sample2.jpg", "_examples/sample3.jpg", "_examples/sample4.jpg",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ex := range examples {
|
||||||
|
file, err := os.Open(ex)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
img, _, err := image.Decode(file)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
for _, method := range methods {
|
||||||
|
methodStr := runtime.FuncForPC(reflect.ValueOf(method).Pointer()).Name()
|
||||||
|
|
||||||
|
hash, err := method(img)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
hex := hash.String()
|
||||||
|
// len(kind) == 1, len(":") == 1, len(hash) == 16
|
||||||
|
if len(hex) != 18 {
|
||||||
|
t.Errorf("Got invalid hex string '%v'; %v of '%v'", hex, methodStr, ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
reHash, err := ImageHashFromString(hex)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
distance, err := hash.Distance(reHash)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
if distance != 0 {
|
||||||
|
t.Errorf("Original and unserialized objects should be identical, got distance=%v; %v of '%v'", distance, methodStr, ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for ExtIExtImageHash
|
||||||
|
for _, extMethod := range extMethods {
|
||||||
|
extMethodStr := runtime.FuncForPC(reflect.ValueOf(extMethod).Pointer()).Name()
|
||||||
|
sizeList := []int{8, 16}
|
||||||
|
for _, size := range sizeList {
|
||||||
|
hash, err := extMethod(img, size, size)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
hex := hash.String()
|
||||||
|
// len(kind) == 1, len(":") == 1
|
||||||
|
if len(hex) != size*size/4+2 {
|
||||||
|
t.Errorf("Got invalid hex string '%v'; %v of '%v'", hex, extMethodStr, ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
reHash, err := ExtImageHashFromString(hex)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
distance, err := hash.Distance(reHash)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
if distance != 0 {
|
||||||
|
t.Errorf("Original and unserialized objects should be identical, got distance=%v; %v of '%v'", distance, "ExtPerceptionHash", ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for hashing empty string
|
||||||
|
imageHash, err := ImageHashFromString("")
|
||||||
|
if imageHash != nil {
|
||||||
|
t.Errorf("Expected reHash to be nil, got %v", imageHash)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Should got error for empty string")
|
||||||
|
}
|
||||||
|
extImageHash, err := ExtImageHashFromString("")
|
||||||
|
if extImageHash != nil {
|
||||||
|
t.Errorf("Expected reHash to be nil, got %v", extImageHash)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Should got error for empty string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for hashing invalid (non-hexadecimal) string
|
||||||
|
extImageHash, err = ExtImageHashFromString("k:g")
|
||||||
|
}
|
||||||
|
|
||||||
// func TestDifferentBitSizeHash(t *testing.T) {
|
// func TestDifferentBitSizeHash(t *testing.T) {
|
||||||
// checkErr := func(err error) {
|
// checkErr := func(err error) {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// t.Errorf("%v", err)
|
// t.Errorf("%v", err)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// file, err := os.Open("_examples/images/sample1.jpg")
|
// file, err := os.Open("_examples/sample1.jpg")
|
||||||
// checkErr(err)
|
// checkErr(err)
|
||||||
// defer file.Close()
|
// defer file.Close()
|
||||||
|
|
||||||
@ -101,7 +199,7 @@ func TestDumpAndLoad(t *testing.T) {
|
|||||||
AverageHash, PerceptionHash, DifferenceHash,
|
AverageHash, PerceptionHash, DifferenceHash,
|
||||||
}
|
}
|
||||||
examples := []string{
|
examples := []string{
|
||||||
"_examples/images/sample1.jpg", "_examples/images/sample2.jpg", "_examples/images/sample3.jpg", "_examples/images/sample4.jpg",
|
"_examples/sample1.jpg", "_examples/sample2.jpg", "_examples/sample3.jpg", "_examples/sample4.jpg",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ex := range examples {
|
for _, ex := range examples {
|
||||||
|
148
pool/pool.go
148
pool/pool.go
@ -1,148 +0,0 @@
|
|||||||
package pool
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
minBitSize = 6 // 2**6=64 is a CPU cache line size
|
|
||||||
steps = 20
|
|
||||||
|
|
||||||
minSize = 1 << minBitSize
|
|
||||||
maxSize = 1 << (minBitSize + steps - 1)
|
|
||||||
|
|
||||||
calibrateCallsThreshold = 42000
|
|
||||||
maxPercentile = 0.95
|
|
||||||
)
|
|
||||||
|
|
||||||
// Pool represents byte buffer pool.
|
|
||||||
//
|
|
||||||
// Distinct pools may be used for distinct types of byte buffers.
|
|
||||||
// Properly determined byte buffer types with their own pools may help reducing
|
|
||||||
// memory waste.
|
|
||||||
type Pool struct {
|
|
||||||
calls [steps]uint64
|
|
||||||
calibrating uint64
|
|
||||||
|
|
||||||
defaultSize uint64
|
|
||||||
maxSize uint64
|
|
||||||
|
|
||||||
pool sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultPool Pool
|
|
||||||
|
|
||||||
// Get returns an empty byte buffer from the pool.
|
|
||||||
//
|
|
||||||
// Got byte buffer may be returned to the pool via Put call.
|
|
||||||
// This reduces the number of memory allocations required for byte buffer
|
|
||||||
// management.
|
|
||||||
func Get() *[]uint8 { return defaultPool.Get() }
|
|
||||||
|
|
||||||
// Get returns new byte buffer with zero length.
|
|
||||||
//
|
|
||||||
// The byte buffer may be returned to the pool via Put after the use
|
|
||||||
// in order to minimize GC overhead.
|
|
||||||
func (p *Pool) Get() *[]uint8 {
|
|
||||||
v := p.pool.Get()
|
|
||||||
if v != nil {
|
|
||||||
return v.(*[]uint8)
|
|
||||||
}
|
|
||||||
return &[]uint8{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put returns byte buffer to the pool.
|
|
||||||
//
|
|
||||||
// []uint8.B mustn't be touched after returning it to the pool.
|
|
||||||
// Otherwise data races will occur.
|
|
||||||
func Put(b *[]uint8) { defaultPool.Put(b) }
|
|
||||||
|
|
||||||
// Put releases byte buffer obtained via Get to the pool.
|
|
||||||
//
|
|
||||||
// The buffer mustn't be accessed after returning to the pool.
|
|
||||||
func (p *Pool) Put(b *[]uint8) {
|
|
||||||
idx := index(len(*b))
|
|
||||||
|
|
||||||
if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold {
|
|
||||||
p.calibrate()
|
|
||||||
}
|
|
||||||
|
|
||||||
maxSize := int(atomic.LoadUint64(&p.maxSize))
|
|
||||||
if maxSize == 0 || cap(*b) <= maxSize {
|
|
||||||
p.pool.Put(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pool) calibrate() {
|
|
||||||
if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
a := make(callSizes, 0, steps)
|
|
||||||
var callsSum uint64
|
|
||||||
for i := uint64(0); i < steps; i++ {
|
|
||||||
calls := atomic.SwapUint64(&p.calls[i], 0)
|
|
||||||
callsSum += calls
|
|
||||||
a = append(a, callSize{
|
|
||||||
calls: calls,
|
|
||||||
size: minSize << i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sort.Sort(a)
|
|
||||||
|
|
||||||
defaultSize := a[0].size
|
|
||||||
maxSize := defaultSize
|
|
||||||
|
|
||||||
maxSum := uint64(float64(callsSum) * maxPercentile)
|
|
||||||
callsSum = 0
|
|
||||||
for i := 0; i < steps; i++ {
|
|
||||||
if callsSum > maxSum {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
callsSum += a[i].calls
|
|
||||||
size := a[i].size
|
|
||||||
if size > maxSize {
|
|
||||||
maxSize = size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.StoreUint64(&p.defaultSize, defaultSize)
|
|
||||||
atomic.StoreUint64(&p.maxSize, maxSize)
|
|
||||||
|
|
||||||
atomic.StoreUint64(&p.calibrating, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
type callSize struct {
|
|
||||||
calls uint64
|
|
||||||
size uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type callSizes []callSize
|
|
||||||
|
|
||||||
func (ci callSizes) Len() int {
|
|
||||||
return len(ci)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ci callSizes) Less(i, j int) bool {
|
|
||||||
return ci[i].calls > ci[j].calls
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ci callSizes) Swap(i, j int) {
|
|
||||||
ci[i], ci[j] = ci[j], ci[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func index(n int) int {
|
|
||||||
n--
|
|
||||||
n >>= minBitSize
|
|
||||||
idx := 0
|
|
||||||
for n > 0 {
|
|
||||||
n >>= 1
|
|
||||||
idx++
|
|
||||||
}
|
|
||||||
if idx >= steps {
|
|
||||||
idx = steps - 1
|
|
||||||
}
|
|
||||||
return idx
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user