mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-05 08:46:56 +08:00
201 lines
4.3 KiB
Go
201 lines
4.3 KiB
Go
package sortedset
|
||
|
||
import (
|
||
"errors"
|
||
"strconv"
|
||
)
|
||
|
||
/*
|
||
* ScoreBorder is a struct represents `min` `max` parameter of redis command `ZRANGEBYSCORE`
|
||
* can accept:
|
||
* int or float value, such as 2.718, 2, -2.718, -2 ...
|
||
* exclusive int or float value, such as (2.718, (2, (-2.718, (-2 ...
|
||
* infinity: +inf, -inf, inf(same as +inf)
|
||
*/
|
||
|
||
const (
|
||
scoreNegativeInf int8 = -1
|
||
scorePositiveInf int8 = 1
|
||
lexNegativeInf int8 = '-'
|
||
lexPositiveInf int8 = '+'
|
||
)
|
||
|
||
type Border interface {
|
||
greater(element *Element) bool
|
||
less(element *Element) bool
|
||
getValue() interface{}
|
||
getExclude() bool
|
||
isIntersected(max Border) bool
|
||
}
|
||
|
||
// ScoreBorder represents range of a float value, including: <, <=, >, >=, +inf, -inf
|
||
type ScoreBorder struct {
|
||
Inf int8
|
||
Value float64
|
||
Exclude bool
|
||
}
|
||
|
||
// if max.greater(score) then the score is within the upper border
|
||
// do not use min.greater()
|
||
func (border *ScoreBorder) greater(element *Element) bool {
|
||
value := element.Score
|
||
if border.Inf == scoreNegativeInf {
|
||
return false
|
||
} else if border.Inf == scorePositiveInf {
|
||
return true
|
||
}
|
||
if border.Exclude {
|
||
return border.Value > value
|
||
}
|
||
return border.Value >= value
|
||
}
|
||
|
||
func (border *ScoreBorder) less(element *Element) bool {
|
||
value := element.Score
|
||
if border.Inf == scoreNegativeInf {
|
||
return true
|
||
} else if border.Inf == scorePositiveInf {
|
||
return false
|
||
}
|
||
if border.Exclude {
|
||
return border.Value < value
|
||
}
|
||
return border.Value <= value
|
||
}
|
||
|
||
func (border *ScoreBorder) getValue() interface{} {
|
||
return border.Value
|
||
}
|
||
|
||
func (border *ScoreBorder) getExclude() bool {
|
||
return border.Exclude
|
||
}
|
||
|
||
var scorePositiveInfBorder = &ScoreBorder{
|
||
Inf: scorePositiveInf,
|
||
}
|
||
|
||
var scoreNegativeInfBorder = &ScoreBorder{
|
||
Inf: scoreNegativeInf,
|
||
}
|
||
|
||
// ParseScoreBorder creates ScoreBorder from redis arguments
|
||
func ParseScoreBorder(s string) (Border, error) {
|
||
if s == "inf" || s == "+inf" {
|
||
return scorePositiveInfBorder, nil
|
||
}
|
||
if s == "-inf" {
|
||
return scoreNegativeInfBorder, nil
|
||
}
|
||
if s[0] == '(' {
|
||
value, err := strconv.ParseFloat(s[1:], 64)
|
||
if err != nil {
|
||
return nil, errors.New("ERR min or max is not a float")
|
||
}
|
||
return &ScoreBorder{
|
||
Inf: 0,
|
||
Value: value,
|
||
Exclude: true,
|
||
}, nil
|
||
}
|
||
value, err := strconv.ParseFloat(s, 64)
|
||
if err != nil {
|
||
return nil, errors.New("ERR min or max is not a float")
|
||
}
|
||
return &ScoreBorder{
|
||
Inf: 0,
|
||
Value: value,
|
||
Exclude: false,
|
||
}, nil
|
||
}
|
||
|
||
func (border *ScoreBorder) isIntersected(max Border) bool {
|
||
minValue := border.Value
|
||
maxValue := max.(*ScoreBorder).Value
|
||
return minValue > maxValue || (minValue == maxValue && (border.getExclude() || max.getExclude()))
|
||
}
|
||
|
||
// LexBorder represents range of a string value, including: <, <=, >, >=, +, -
|
||
type LexBorder struct {
|
||
Inf int8
|
||
Value string
|
||
Exclude bool
|
||
}
|
||
|
||
// if max.greater(lex) then the lex is within the upper border
|
||
// do not use min.greater()
|
||
func (border *LexBorder) greater(element *Element) bool {
|
||
value := element.Member
|
||
if border.Inf == lexNegativeInf {
|
||
return false
|
||
} else if border.Inf == lexPositiveInf {
|
||
return true
|
||
}
|
||
if border.Exclude {
|
||
return border.Value > value
|
||
}
|
||
return border.Value >= value
|
||
}
|
||
|
||
func (border *LexBorder) less(element *Element) bool {
|
||
value := element.Member
|
||
if border.Inf == lexNegativeInf {
|
||
return true
|
||
} else if border.Inf == lexPositiveInf {
|
||
return false
|
||
}
|
||
if border.Exclude {
|
||
return border.Value < value
|
||
}
|
||
return border.Value <= value
|
||
}
|
||
|
||
func (border *LexBorder) getValue() interface{} {
|
||
return border.Value
|
||
}
|
||
|
||
func (border *LexBorder) getExclude() bool {
|
||
return border.Exclude
|
||
}
|
||
|
||
var lexPositiveInfBorder = &LexBorder{
|
||
Inf: lexPositiveInf,
|
||
}
|
||
|
||
var lexNegativeInfBorder = &LexBorder{
|
||
Inf: lexNegativeInf,
|
||
}
|
||
|
||
// ParseLexBorder creates LexBorder from redis arguments
|
||
func ParseLexBorder(s string) (Border, error) {
|
||
if s == "+" {
|
||
return lexPositiveInfBorder, nil
|
||
}
|
||
if s == "-" {
|
||
return lexNegativeInfBorder, nil
|
||
}
|
||
if s[0] == '(' {
|
||
return &LexBorder{
|
||
Inf: 0,
|
||
Value: s[1:],
|
||
Exclude: true,
|
||
}, nil
|
||
}
|
||
|
||
if s[0] == '[' {
|
||
return &LexBorder{
|
||
Inf: 0,
|
||
Value: s[1:],
|
||
Exclude: false,
|
||
}, nil
|
||
}
|
||
|
||
return nil, errors.New("ERR min or max not valid string range item")
|
||
}
|
||
|
||
func (border *LexBorder) isIntersected(max Border) bool {
|
||
minValue := border.Value
|
||
maxValue := max.(*LexBorder).Value
|
||
return border.Inf == '+' || minValue > maxValue || (minValue == maxValue && (border.getExclude() || max.getExclude()))
|
||
}
|