wangjia184 / sortedset

An ordered collection implemented in Golang with O(log(N)) time complexity on adding / searching / removing

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

GetByScoreRange search reverse will return empty header node, when there is no smaller score than high bound score.

icey129 opened this issue · comments

When GetByScoreRange with start > end, and start < min(score) in SortedSet, it will return SortedSet.header created by New() function. This confuses the caller and cause unexpected exception.

 func New() *SortedSet {
	sortedSet := SortedSet{
		level: 1,
		dict:  make(map[string]*SortedSetNode),
	}
	sortedSet.header = createNode(SKIPLIST_MAXLEVEL, 0, "", nil)
	return &sortedSet
}

The logic of reverse search is:

if reverse { // search from end to start
		**x := this.header**

		if excludeEnd {
			for i := this.level - 1; i >= 0; i-- {
				for x.level[i].forward != nil &&
					x.level[i].forward.score < end {
					x = x.level[i].forward
				}
			}
		} else {
			for i := this.level - 1; i >= 0; i-- {
				for x.level[i].forward != nil &&
					x.level[i].forward.score <= end {
					x = x.level[i].forward
				}
			}
		}

		for x != nil && limit > 0 {
			if excludeStart {
				if x.score <= start {
					break
				}
			} else {
				if x.score < start {
					break
				}
			}

			next := x.backward

			**nodes = append(nodes, x)**
			limit--

			x = next
		}
	} 

For example, run the following test will retun the unexpected header create by New() function.

func TestGetByScoreRange(t *testing.T) {
	var (
		set   = sortedset.New()
		datas = []struct {
			key   string
			score sortedset.SCORE
			value int
		}{
			{
				key:   "100",
				score: 100,
				value: 100,
			},
			{
				key:   "103",
				score: 103,
				value: 103,
			},
			{
				key:   "105-1",
				score: 105,
				value: 105,
			},
			{
				key:   "105-2",
				score: 105,
				value: 105,
			},
			{
				key:   "107",
				score: 107,
				value: 107,
			},
		}
	)
	for _, v := range datas {
		set.AddOrUpdate(v.key, v.score, v.value)
	}
	nodes := set.GetByScoreRange(sortedset.SCORE(80), sortedset.SCORE(0), nil)
	fmt.Println(len(nodes))
	if len(nodes) > 0 {
		t.Errorf("return unexpected node, key=%s, score=%d, value=%v", nodes[0].Key(), nodes[0].Score(), nodes[0].Value)
	}
}