[#2] hrw: add typed methods for hashers #3
2 changed files with 165 additions and 0 deletions
34
hrw.go
34
hrw.go
|
@ -83,6 +83,17 @@ func SortSliceByValue(slice interface{}, hash uint64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SortHasherSliceByValue receives []Hasher and hash to sort by value-distance.
|
||||||
|
func SortHasherSliceByValue[T Hasher](slice []T, hash uint64) {
|
||||||
|
rule := prepareHasherRule(slice)
|
||||||
|
if rule != nil {
|
||||||
|
swap := func(i, j int) {
|
||||||
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
}
|
||||||
|
sortByDistance(len(rule), false, rule, hash, swap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SortSliceByWeightValue received []T, weights and hash to sort by value-distance * weights
|
// SortSliceByWeightValue received []T, weights and hash to sort by value-distance * weights
|
||||||
func SortSliceByWeightValue(slice interface{}, weights []float64, hash uint64) {
|
func SortSliceByWeightValue(slice interface{}, weights []float64, hash uint64) {
|
||||||
rule := prepareRule(slice)
|
rule := prepareRule(slice)
|
||||||
|
@ -92,6 +103,17 @@ func SortSliceByWeightValue(slice interface{}, weights []float64, hash uint64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SortHasherSliceByWeightValue receives []Hasher, weights and hash to sort by value-distance * weights.
|
||||||
|
func SortHasherSliceByWeightValue[T Hasher](slice []T, weights []float64, hash uint64) {
|
||||||
|
rule := prepareHasherRule(slice)
|
||||||
|
if rule != nil {
|
||||||
|
swap := func(i, j int) {
|
||||||
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
}
|
||||||
|
sortByWeight(len(slice), false, rule, weights, hash, swap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SortSliceByIndex received []T and hash to sort by index-distance
|
// SortSliceByIndex received []T and hash to sort by index-distance
|
||||||
func SortSliceByIndex(slice interface{}, hash uint64) {
|
func SortSliceByIndex(slice interface{}, hash uint64) {
|
||||||
length := reflect.ValueOf(slice).Len()
|
length := reflect.ValueOf(slice).Len()
|
||||||
|
@ -199,6 +221,18 @@ func prepareRule(slice interface{}) []uint64 {
|
||||||
return rule
|
return rule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prepareHasherRule[T Hasher](hashers []T) []uint64 {
|
||||||
|
length := len(hashers)
|
||||||
|
if length == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result := make([]uint64, length)
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
result[i] = hashers[i].Hash()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// ValidateWeights checks if weights are normalized between 0.0 and 1.0
|
// ValidateWeights checks if weights are normalized between 0.0 and 1.0
|
||||||
func ValidateWeights(weights []float64) error {
|
func ValidateWeights(weights []float64) error {
|
||||||
for i := range weights {
|
for i := range weights {
|
||||||
|
|
131
hrw_test.go
131
hrw_test.go
|
@ -131,6 +131,23 @@ func TestSortSliceByValueHasher(t *testing.T) {
|
||||||
require.Equal(t, expect, actual)
|
require.Equal(t, expect, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSortHasherSliceByValue(t *testing.T) {
|
||||||
|
actual := []hashString{"a", "b", "c", "d", "e", "f"}
|
||||||
|
expect := []hashString{"d", "f", "c", "b", "a", "e"}
|
||||||
|
hash := Hash(testKey)
|
||||||
|
SortHasherSliceByValue(actual, hash)
|
||||||
|
require.EqualValues(t, expect, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSortHasherSliceByWeightValue(t *testing.T) {
|
||||||
|
actual := []hashString{"a", "b", "c", "d", "e", "f"}
|
||||||
|
weights := []float64{1.0, 1.0, 1.0, 1.0, 1.0, 1.0}
|
||||||
|
expect := []hashString{"d", "f", "c", "b", "a", "e"}
|
||||||
|
hash := Hash(testKey)
|
||||||
|
SortHasherSliceByWeightValue(actual, weights, hash)
|
||||||
|
require.EqualValues(t, expect, actual)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSortSliceByValueIntSlice(t *testing.T) {
|
func TestSortSliceByValueIntSlice(t *testing.T) {
|
||||||
cases := []slices{
|
cases := []slices{
|
||||||
{
|
{
|
||||||
|
@ -636,6 +653,36 @@ func BenchmarkSortByValue_fnv_1000(b *testing.B) {
|
||||||
benchmarkSortByValue(b, 1000, hash)
|
benchmarkSortByValue(b, 1000, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByValue_Reflection_fnv_10(b *testing.B) {
|
||||||
|
hash := Hash(testKey)
|
||||||
|
benchmarkSortHashersByValueReflection(b, 10, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByValue_Reflection_fnv_100(b *testing.B) {
|
||||||
|
hash := Hash(testKey)
|
||||||
|
benchmarkSortHashersByValueReflection(b, 100, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByValue_Reflection_fnv_1000(b *testing.B) {
|
||||||
|
hash := Hash(testKey)
|
||||||
|
benchmarkSortHashersByValueReflection(b, 1000, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByValue_Typed_fnv_10(b *testing.B) {
|
||||||
|
hash := Hash(testKey)
|
||||||
|
benchmarkSortHashersByValueTyped(b, 10, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByValue_Typed_fnv_100(b *testing.B) {
|
||||||
|
hash := Hash(testKey)
|
||||||
|
benchmarkSortHashersByValueTyped(b, 100, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByValue_Typed_fnv_1000(b *testing.B) {
|
||||||
|
hash := Hash(testKey)
|
||||||
|
benchmarkSortHashersByValueTyped(b, 1000, hash)
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkSortByWeight_fnv_10(b *testing.B) {
|
func BenchmarkSortByWeight_fnv_10(b *testing.B) {
|
||||||
hash := Hash(testKey)
|
hash := Hash(testKey)
|
||||||
_ = benchmarkSortByWeight(b, 10, hash)
|
_ = benchmarkSortByWeight(b, 10, hash)
|
||||||
|
@ -681,6 +728,30 @@ func BenchmarkSortByWeightValue_fnv_1000(b *testing.B) {
|
||||||
benchmarkSortByWeightValue(b, 1000, hash)
|
benchmarkSortByWeightValue(b, 1000, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByWeightValueReflection_fnv_10(b *testing.B) {
|
||||||
|
benchmarkSortHashersByWeightValueRelection(b, 10, Hash(testKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByWeightValueReflection_fnv_100(b *testing.B) {
|
||||||
|
benchmarkSortHashersByWeightValueRelection(b, 100, Hash(testKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByWeightValueReflection_fnv_1000(b *testing.B) {
|
||||||
|
benchmarkSortHashersByWeightValueRelection(b, 100, Hash(testKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByWeightValueTyped_fnv_10(b *testing.B) {
|
||||||
|
benchmarkSortHashersByWeightValueTyped(b, 10, Hash(testKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByWeightValueTyped_fnv_100(b *testing.B) {
|
||||||
|
benchmarkSortHashersByWeightValueTyped(b, 100, Hash(testKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSortHashersByWeightValueTyped_fnv_1000(b *testing.B) {
|
||||||
|
benchmarkSortHashersByWeightValueTyped(b, 100, Hash(testKey))
|
||||||
|
}
|
||||||
|
|
||||||
func benchmarkSort(b *testing.B, n int, hash uint64) uint64 {
|
func benchmarkSort(b *testing.B, n int, hash uint64) uint64 {
|
||||||
servers := make([]uint64, n)
|
servers := make([]uint64, n)
|
||||||
for i := uint64(0); i < uint64(len(servers)); i++ {
|
for i := uint64(0); i < uint64(len(servers)); i++ {
|
||||||
|
@ -774,3 +845,63 @@ func benchmarkSortByWeightValue(b *testing.B, n int, hash uint64) {
|
||||||
SortSliceByWeightValue(servers, weights, hash)
|
SortSliceByWeightValue(servers, weights, hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func benchmarkSortHashersByWeightValueRelection(b *testing.B, n int, hash uint64) {
|
||||||
|
servers := make([]hashString, n)
|
||||||
|
weights := make([]float64, n)
|
||||||
|
for i := uint64(0); i < uint64(len(servers)); i++ {
|
||||||
|
weights[i] = float64(uint64(n)-i) / float64(n)
|
||||||
|
servers[i] = hashString("localhost:" + strconv.FormatUint(60000-i, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SortSliceByWeightValue(servers, weights, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkSortHashersByWeightValueTyped(b *testing.B, n int, hash uint64) {
|
||||||
|
servers := make([]hashString, n)
|
||||||
|
weights := make([]float64, n)
|
||||||
|
for i := uint64(0); i < uint64(len(servers)); i++ {
|
||||||
|
weights[i] = float64(uint64(n)-i) / float64(n)
|
||||||
|
servers[i] = hashString("localhost:" + strconv.FormatUint(60000-i, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SortHasherSliceByWeightValue(servers, weights, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkSortHashersByValueReflection(b *testing.B, n int, hash uint64) {
|
||||||
|
servers := make([]hashString, n)
|
||||||
|
for i := uint64(0); i < uint64(len(servers)); i++ {
|
||||||
|
servers[i] = hashString("localhost:" + strconv.FormatUint(60000-i, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SortSliceByValue(servers, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkSortHashersByValueTyped(b *testing.B, n int, hash uint64) {
|
||||||
|
servers := make([]hashString, n)
|
||||||
|
for i := uint64(0); i < uint64(len(servers)); i++ {
|
||||||
|
servers[i] = hashString("localhost:" + strconv.FormatUint(60000-i, 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SortHasherSliceByValue(servers, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue