github.com/hdt3213/godis@v1.2.9/datastruct/sortedset/sortedset.go (about) 1 package sortedset 2 3 import ( 4 "strconv" 5 ) 6 7 // SortedSet is a set which keys sorted by bound score 8 type SortedSet struct { 9 dict map[string]*Element 10 skiplist *skiplist 11 } 12 13 // Make makes a new SortedSet 14 func Make() *SortedSet { 15 return &SortedSet{ 16 dict: make(map[string]*Element), 17 skiplist: makeSkiplist(), 18 } 19 } 20 21 // Add puts member into set, and returns whether has inserted new node 22 func (sortedSet *SortedSet) Add(member string, score float64) bool { 23 element, ok := sortedSet.dict[member] 24 sortedSet.dict[member] = &Element{ 25 Member: member, 26 Score: score, 27 } 28 if ok { 29 if score != element.Score { 30 sortedSet.skiplist.remove(member, element.Score) 31 sortedSet.skiplist.insert(member, score) 32 } 33 return false 34 } 35 sortedSet.skiplist.insert(member, score) 36 return true 37 } 38 39 // Len returns number of members in set 40 func (sortedSet *SortedSet) Len() int64 { 41 return int64(len(sortedSet.dict)) 42 } 43 44 // Get returns the given member 45 func (sortedSet *SortedSet) Get(member string) (element *Element, ok bool) { 46 element, ok = sortedSet.dict[member] 47 if !ok { 48 return nil, false 49 } 50 return element, true 51 } 52 53 // Remove removes the given member from set 54 func (sortedSet *SortedSet) Remove(member string) bool { 55 v, ok := sortedSet.dict[member] 56 if ok { 57 sortedSet.skiplist.remove(member, v.Score) 58 delete(sortedSet.dict, member) 59 return true 60 } 61 return false 62 } 63 64 // GetRank returns the rank of the given member, sort by ascending order, rank starts from 0 65 func (sortedSet *SortedSet) GetRank(member string, desc bool) (rank int64) { 66 element, ok := sortedSet.dict[member] 67 if !ok { 68 return -1 69 } 70 r := sortedSet.skiplist.getRank(member, element.Score) 71 if desc { 72 r = sortedSet.skiplist.length - r 73 } else { 74 r-- 75 } 76 return r 77 } 78 79 // ForEach visits each member which rank within [start, stop), sort by ascending order, rank starts from 0 80 func (sortedSet *SortedSet) ForEach(start int64, stop int64, desc bool, consumer func(element *Element) bool) { 81 size := int64(sortedSet.Len()) 82 if start < 0 || start >= size { 83 panic("illegal start " + strconv.FormatInt(start, 10)) 84 } 85 if stop < start || stop > size { 86 panic("illegal end " + strconv.FormatInt(stop, 10)) 87 } 88 89 // find start node 90 var node *node 91 if desc { 92 node = sortedSet.skiplist.tail 93 if start > 0 { 94 node = sortedSet.skiplist.getByRank(int64(size - start)) 95 } 96 } else { 97 node = sortedSet.skiplist.header.level[0].forward 98 if start > 0 { 99 node = sortedSet.skiplist.getByRank(int64(start + 1)) 100 } 101 } 102 103 sliceSize := int(stop - start) 104 for i := 0; i < sliceSize; i++ { 105 if !consumer(&node.Element) { 106 break 107 } 108 if desc { 109 node = node.backward 110 } else { 111 node = node.level[0].forward 112 } 113 } 114 } 115 116 // Range returns members which rank within [start, stop), sort by ascending order, rank starts from 0 117 func (sortedSet *SortedSet) Range(start int64, stop int64, desc bool) []*Element { 118 sliceSize := int(stop - start) 119 slice := make([]*Element, sliceSize) 120 i := 0 121 sortedSet.ForEach(start, stop, desc, func(element *Element) bool { 122 slice[i] = element 123 i++ 124 return true 125 }) 126 return slice 127 } 128 129 // Count returns the number of members which score within the given border 130 func (sortedSet *SortedSet) Count(min *ScoreBorder, max *ScoreBorder) int64 { 131 var i int64 = 0 132 // ascending order 133 sortedSet.ForEach(0, sortedSet.Len(), false, func(element *Element) bool { 134 gtMin := min.less(element.Score) // greater than min 135 if !gtMin { 136 // has not into range, continue foreach 137 return true 138 } 139 ltMax := max.greater(element.Score) // less than max 140 if !ltMax { 141 // break through score border, break foreach 142 return false 143 } 144 // gtMin && ltMax 145 i++ 146 return true 147 }) 148 return i 149 } 150 151 // ForEachByScore visits members which score within the given border 152 func (sortedSet *SortedSet) ForEachByScore(min *ScoreBorder, max *ScoreBorder, offset int64, limit int64, desc bool, consumer func(element *Element) bool) { 153 // find start node 154 var node *node 155 if desc { 156 node = sortedSet.skiplist.getLastInScoreRange(min, max) 157 } else { 158 node = sortedSet.skiplist.getFirstInScoreRange(min, max) 159 } 160 161 for node != nil && offset > 0 { 162 if desc { 163 node = node.backward 164 } else { 165 node = node.level[0].forward 166 } 167 offset-- 168 } 169 170 // A negative limit returns all elements from the offset 171 for i := 0; (i < int(limit) || limit < 0) && node != nil; i++ { 172 if !consumer(&node.Element) { 173 break 174 } 175 if desc { 176 node = node.backward 177 } else { 178 node = node.level[0].forward 179 } 180 if node == nil { 181 break 182 } 183 gtMin := min.less(node.Element.Score) // greater than min 184 ltMax := max.greater(node.Element.Score) 185 if !gtMin || !ltMax { 186 break // break through score border 187 } 188 } 189 } 190 191 // RangeByScore returns members which score within the given border 192 // param limit: <0 means no limit 193 func (sortedSet *SortedSet) RangeByScore(min *ScoreBorder, max *ScoreBorder, offset int64, limit int64, desc bool) []*Element { 194 if limit == 0 || offset < 0 { 195 return make([]*Element, 0) 196 } 197 slice := make([]*Element, 0) 198 sortedSet.ForEachByScore(min, max, offset, limit, desc, func(element *Element) bool { 199 slice = append(slice, element) 200 return true 201 }) 202 return slice 203 } 204 205 // RemoveByScore removes members which score within the given border 206 func (sortedSet *SortedSet) RemoveByScore(min *ScoreBorder, max *ScoreBorder) int64 { 207 removed := sortedSet.skiplist.RemoveRangeByScore(min, max, 0) 208 for _, element := range removed { 209 delete(sortedSet.dict, element.Member) 210 } 211 return int64(len(removed)) 212 } 213 214 func (sortedSet *SortedSet) PopMin(count int) []*Element { 215 first := sortedSet.skiplist.getFirstInScoreRange(negativeInfBorder, positiveInfBorder) 216 if first == nil { 217 return nil 218 } 219 border := &ScoreBorder{ 220 Value: first.Score, 221 Exclude: false, 222 } 223 removed := sortedSet.skiplist.RemoveRangeByScore(border, positiveInfBorder, count) 224 for _, element := range removed { 225 delete(sortedSet.dict, element.Member) 226 } 227 return removed 228 } 229 230 // RemoveByRank removes member ranking within [start, stop) 231 // sort by ascending order and rank starts from 0 232 func (sortedSet *SortedSet) RemoveByRank(start int64, stop int64) int64 { 233 removed := sortedSet.skiplist.RemoveRangeByRank(start+1, stop+1) 234 for _, element := range removed { 235 delete(sortedSet.dict, element.Member) 236 } 237 return int64(len(removed)) 238 }