diff --git a/hrw.go b/hrw.go index 2effa3a..c874917 100644 --- a/hrw.go +++ b/hrw.go @@ -85,10 +85,15 @@ 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 { - sortHasherByDistance(slice, false, rule, hash) + if len(slice) == 0 { + return } + + dist := make([]uint64, len(slice)) + for i := range dist { + dist[i] = distance(slice[i].Hash(), hash) + } + sortHasherByDistance(slice, false, dist) } // SortSliceByWeightValue received []T, weights and hash to sort by value-distance * weights @@ -102,49 +107,28 @@ 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 { - sortHasherByWeight(slice, false, rule, weights, hash) - } -} - -// sortHasherByDistance is similar to sortByDistance but accepts slice directly. -func sortHasherByDistance[T Hasher](slice []T, byIndex bool, nodes []uint64, hash uint64) { - dist := make([]uint64, len(slice)) - for i := range dist { - dist[i] = getDistance(byIndex, i, nodes, hash) + if len(slice) == 0 { + return } - s := &sorter{ - l: len(slice), - swap: func(i, j int) { - slice[i], slice[j] = slice[j], slice[i] - dist[i], dist[j] = dist[j], dist[i] - }, - less: func(i, j int) bool { - return dist[i] < dist[j] - }, - } - sort.Sort(s) -} - -// sortHasherByWeight is similar to sortByWeight but accepts slice directly. -func sortHasherByWeight[T Hasher](slice []T, byIndex bool, nodes []uint64, weights []float64, hash uint64) { - // if all nodes have the same distance then sort uniformly if allSameF64(weights) { - sortHasherByDistance(slice, byIndex, nodes, hash) + dist := make([]uint64, len(slice)) + for i := range dist { + dist[i] = distance(slice[i].Hash(), hash) + } + sortHasherByDistance(slice, false, dist) return } dist := make([]float64, len(slice)) for i := range dist { - d := getDistance(byIndex, i, nodes, hash) + d := distance(slice[i].Hash(), hash) // `maxUint64 - distance` makes the shorter distance more valuable // it is necessary for operation with normalized values dist[i] = float64(^uint64(0)-d) * weights[i] } - s := &sorter{ + sort.Sort(&sorter{ l: len(slice), swap: func(i, j int) { slice[i], slice[j] = slice[j], slice[i] @@ -153,8 +137,21 @@ func sortHasherByWeight[T Hasher](slice []T, byIndex bool, nodes []uint64, weigh less: func(i, j int) bool { return dist[i] > dist[j] // higher distance must be placed lower to be first }, - } - sort.Sort(s) + }) +} + +// sortHasherByDistance is similar to sortByDistance but accepts slice directly. +func sortHasherByDistance[T Hasher](slice []T, byIndex bool, dist []uint64) { + sort.Sort(&sorter{ + l: len(slice), + swap: func(i, j int) { + slice[i], slice[j] = slice[j], slice[i] + dist[i], dist[j] = dist[j], dist[i] + }, + less: func(i, j int) bool { + return dist[i] < dist[j] + }, + }) } // SortSliceByIndex received []T and hash to sort by index-distance @@ -264,18 +261,6 @@ func prepareRule(slice interface{}) []uint64 { 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 func ValidateWeights(weights []float64) error { for i := range weights {