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  }