github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/sets/zset/skiplist.go (about) 1 package zset 2 3 import ( 4 "math" 5 "unsafe" 6 7 "github.com/songzhibin97/go-baseutils/base/bcomparator" 8 "github.com/songzhibin97/go-baseutils/sys/fastrand" 9 ) 10 11 // 12 // Skip list implementation. 13 // 14 15 const ( 16 maxLevel = 32 // same to ZSKIPLIST_MAXLEVEL, should be enough for 2^64 elements 17 probability = 0.25 // same to ZSKIPLIST_P, 1/4 18 ) 19 20 // listNode is node of list. 21 type listNode[K comparable] struct { 22 score float64 // key for sorting, which is allowed to be repeated 23 value K 24 prev *listNode[K] // back pointer that only available at level 1 25 level int // the length of optionalArray 26 oparr optionalArray 27 } 28 29 func newListNode[K comparable](score float64, value K, level int) *listNode[K] { 30 node := &listNode[K]{ 31 score: score, 32 value: value, 33 level: level, 34 } 35 node.oparr.init(level) 36 return node 37 } 38 39 func (n *listNode[K]) loadNext(i int) *listNode[K] { 40 return (*listNode[K])(n.oparr.loadNext(i)) 41 } 42 43 func (n *listNode[K]) storeNext(i int, node *listNode[K]) { 44 n.oparr.storeNext(i, unsafe.Pointer(node)) 45 } 46 47 func (n *listNode[K]) loadSpan(i int) int { 48 return n.oparr.loadSpan(i) 49 } 50 51 func (n *listNode[K]) storeSpan(i int, span int) { 52 n.oparr.storeSpan(i, span) 53 } 54 55 func (n *listNode[K]) loadNextAndSpan(i int) (*listNode[K], int) { 56 return n.loadNext(i), n.loadSpan(i) 57 } 58 59 func (n *listNode[K]) storeNextAndSpan(i int, next *listNode[K], span int) { 60 n.storeNext(i, next) 61 n.storeSpan(i, span) 62 } 63 64 func (n *listNode[K]) lessThan(score float64, value K, comparator bcomparator.Comparator[K]) bool { 65 if n.score < score { 66 return true 67 } 68 if n.score == score { 69 return comparator(n.value, value) < 0 70 } 71 return false 72 } 73 74 func (n *listNode[K]) lessEqual(score float64, value K, comparator bcomparator.Comparator[K]) bool { 75 if n.score < score { 76 return true 77 } 78 if n.score == score { 79 return comparator(n.value, value) <= 0 80 } 81 return false 82 } 83 84 func (n *listNode[K]) equal(score float64, value K) bool { 85 return n.value == value && n.score == score 86 } 87 88 // list is a specialized skip list implementation for sorted set. 89 // 90 // It is almost implement the original 91 // algorithm described by William Pugh in " Lists: A Probabilistic 92 // Alternative to Balanced Trees", modified in three ways: 93 // a) this implementation allows for repeated scores. 94 // b) the comparison is not just by key (our 'score') but by satellite data(?). 95 // c) there is a back pointer, so it's a doubly linked list with the back 96 // pointers being only at "level 1". This allows to traverse the list 97 // from tail to head, useful for RevRange. 98 type list[K comparable] struct { 99 header *listNode[K] 100 tail *listNode[K] 101 length int 102 highestLevel int // highest level for now 103 comparator bcomparator.Comparator[K] 104 } 105 106 func newList[K comparable](comparator bcomparator.Comparator[K]) *list[K] { 107 var zero K 108 l := &list[K]{ 109 header: newListNode[K](-math.MaxFloat64, zero, maxLevel), // FIXME: 110 highestLevel: 1, 111 comparator: comparator, 112 } 113 return l 114 } 115 116 // Insert inserts a new node in the skiplist. Assumes the element does not already 117 // exist (up to the caller to enforce that). 118 func (l *list[K]) Insert(score float64, value K) *listNode[K] { 119 var ( 120 update [maxLevel]*listNode[K] 121 rank [maxLevel + 1]int // +1 for eliminating a boundary judgment 122 ) 123 124 x := l.header 125 for i := l.highestLevel - 1; i >= 0; i-- { 126 rank[i] = rank[i+1] // also fine when i == maxLevel - 1 127 next := x.loadNext(i) 128 for next != nil && next.lessThan(score, value, l.comparator) { 129 rank[i] += x.loadSpan(i) 130 x = next 131 next = x.loadNext(i) 132 } 133 update[i] = x 134 } 135 136 // We assume the element is not already inside, since we allow duplicated 137 // scores, reinserting the same element should never happen since the 138 // caller of Add() should test in the hash table if the element is 139 // already inside or not. 140 level := l.randomLevel() 141 if level > l.highestLevel { 142 // Create higher levels. 143 for i := l.highestLevel; i < level; i++ { 144 rank[i] = 0 145 update[i] = l.header 146 update[i].storeSpan(i, l.length) 147 } 148 l.highestLevel = level 149 } 150 x = newListNode(score, value, level) 151 for i := 0; i < level; i++ { 152 // update --> x --> update.next 153 x.storeNext(i, update[i].loadNext(i)) 154 update[i].storeNext(i, x) 155 // update[i].span is splitted to: new update[i].span and x.span 156 x.storeSpan(i, update[i].loadSpan(i)-(rank[0]-rank[i])) 157 update[i].storeSpan(i, (rank[0]-rank[i])+1) 158 } 159 // Increment span for untouched levels. 160 for i := level; i < l.highestLevel; i++ { 161 update[i].storeSpan(i, update[i].loadSpan(i)+1) 162 } 163 164 // Update back pointer. 165 if update[0] != l.header { 166 x.prev = update[0] 167 } 168 169 if next := x.loadNext(0); next != nil { // not tail of skiplist 170 next.prev = x 171 } else { 172 l.tail = x 173 } 174 l.length++ 175 176 return x 177 } 178 179 // randomLevel returns a level between [1, maxLevel] for insertion. 180 func (l *list[K]) randomLevel() int { 181 level := 1 182 for fastrand.Uint32n(1/probability) == 0 { 183 level++ 184 } 185 if level > maxLevel { 186 return maxLevel 187 } 188 return level 189 } 190 191 // Rank finds the rank for an element by both score and value. 192 // Returns 0 when the element cannot be found, rank otherwise. 193 // 194 // NOTE: the rank is 1-based due to the span of l->header to the 195 // first element. 196 func (l *list[K]) Rank(score float64, value K) int { 197 rank := 0 198 x := l.header 199 for i := l.highestLevel - 1; i >= 0; i-- { 200 next := x.loadNext(i) 201 for next != nil && next.lessEqual(score, value, l.comparator) { 202 rank += x.loadSpan(i) 203 x = next 204 next = x.loadNext(i) 205 } 206 207 // x might be equal to l->header, so test if obj is non-nil 208 // TODO: Why not use if x != l.header? 209 if x.equal(score, value) { 210 return rank 211 } 212 } 213 return 0 214 } 215 216 // deleteNode is a internal function for deleting node x in O(1) time by giving a 217 // update position matrix. 218 func (l *list[K]) deleteNode(x *listNode[K], update *[maxLevel]*listNode[K]) { 219 for i := 0; i < l.highestLevel; i++ { 220 if update[i].loadNext(i) == x { 221 // Remove x, updaet[i].span = updaet[i].span + x.span - 1 (x removed). 222 next, span := x.loadNextAndSpan(i) 223 span += update[i].loadSpan(i) - 1 224 update[i].storeNextAndSpan(i, next, span) 225 } else { 226 // x does not appear on this level, just update span. 227 update[i].storeSpan(i, update[i].loadSpan(i)-1) 228 } 229 } 230 if next := x.loadNext(0); next != nil { // not tail of skiplist 231 next.prev = x.prev 232 } else { 233 l.tail = x.prev 234 } 235 for l.highestLevel > 1 && l.header.loadNext(l.highestLevel-1) != nil { 236 // Clear the pointer and span for safety. 237 l.header.storeNextAndSpan(l.highestLevel-1, nil, 0) 238 l.highestLevel-- 239 } 240 l.length-- 241 } 242 243 // Delete deletes an element with matching score/element from the skiplist. 244 // The deleted node is returned if the node was found, otherwise 0 is returned. 245 func (l *list[K]) Delete(score float64, value K) *listNode[K] { 246 var update [maxLevel]*listNode[K] 247 248 x := l.header 249 for i := l.highestLevel - 1; i >= 0; i-- { 250 next := x.loadNext(i) 251 for next != nil && next.lessThan(score, value, l.comparator) { 252 x = next 253 next = x.loadNext(i) 254 } 255 update[i] = x 256 } 257 x = x.loadNext(0) 258 if x != nil && x.equal(score, value) { 259 l.deleteNode(x, &update) 260 return x 261 } 262 return nil // not found 263 } 264 265 // UpdateScore updates the score of an element inside the sorted set skiplist. 266 // 267 // NOTE: the element must exist and must match 'score'. 268 // This function does not update the score in the hash table side, the 269 // caller should take care of it. 270 // 271 // NOTE: this function attempts to just update the node, in case after 272 // the score update, the node would be exactly at the same position. 273 // Otherwise the skiplist is modified by removing and re-adding a new 274 // element, which is more costly. 275 // 276 // The function returns the updated element skiplist node pointer. 277 func (l *list[K]) UpdateScore(oldScore float64, value K, newScore float64) *listNode[K] { 278 var update [maxLevel]*listNode[K] 279 280 x := l.header 281 for i := l.highestLevel - 1; i >= 0; i-- { 282 next := x.loadNext(i) 283 for next != nil && next.lessThan(oldScore, value, l.comparator) { 284 x = next 285 next = x.loadNext(i) 286 } 287 update[i] = x 288 } 289 290 // Jump to our element: note that this function assumes that the 291 // element with the matching score exists. 292 x = x.loadNext(0) 293 294 // Fastpath: If the node, after the score update, would be still exactly 295 // at the same position, we can just update the score without 296 // actually removing and re-inserting the element in the skiplist. 297 if next := x.loadNext(0); (x.prev == nil || x.prev.score < newScore) && 298 (next == nil || next.score > newScore) { 299 x.score = newScore 300 return x 301 } 302 303 // No way to reuse the old node: we need to remove and insert a new 304 // one at a different place. 305 v := x.value 306 l.deleteNode(x, &update) 307 newNode := l.Insert(newScore, v) 308 return newNode 309 } 310 311 func greaterThanMin(value float64, min float64, ex bool) bool { 312 if ex { 313 return value > min 314 } 315 return value >= min 316 } 317 318 func lessThanMax(value float64, max float64, ex bool) bool { 319 if ex { 320 return value < max 321 } 322 return value <= max 323 } 324 325 // DeleteRangeByScore deletes all the elements with score between min and max 326 // from the skiplist. 327 // Both min and max can be inclusive or exclusive (see RangeOpt). 328 // When inclusive a score >= min && score <= max is deleted. 329 // 330 // This function returns count of deleted elements. 331 func (l *list[K]) DeleteRangeByScore(min, max float64, opt RangeOpt, dict map[K]float64) []Node[K] { 332 var ( 333 update [maxLevel]*listNode[K] 334 removed []Node[K] 335 ) 336 337 x := l.header 338 for i := l.highestLevel - 1; i >= 0; i-- { 339 next := x.loadNext(i) 340 for next != nil && !greaterThanMin(next.score, min, opt.ExcludeMin) { 341 x = next 342 next = x.loadNext(i) 343 } 344 update[i] = x 345 } 346 347 // Current node is the last with score not greater than min. 348 x = x.loadNext(0) 349 350 // Delete nodes in range. 351 for x != nil && lessThanMax(x.score, max, opt.ExcludeMax) { 352 next := x.loadNext(0) 353 l.deleteNode(x, &update) 354 delete(dict, x.value) 355 removed = append(removed, Node[K]{ 356 Value: x.value, 357 Score: x.score, 358 }) 359 x = next 360 } 361 362 return removed 363 } 364 365 // Delete all the elements with rank between start and end from the skiplist. 366 // Start and end are inclusive. 367 // 368 // NOTE: start and end need to be 1-based 369 func (l *list[K]) DeleteRangeByRank(start, end int, dict map[K]float64) []Node[K] { 370 var ( 371 update [maxLevel]*listNode[K] 372 removed []Node[K] 373 traversed int 374 ) 375 376 x := l.header 377 for i := l.highestLevel - 1; i >= 0; i-- { 378 next, span := x.loadNextAndSpan(i) 379 for next != nil && traversed+span < start { 380 traversed += span 381 x = next 382 next, span = x.loadNextAndSpan(i) 383 } 384 update[i] = x 385 } 386 387 traversed++ 388 x = x.loadNext(0) 389 // Delete nodes in range. 390 for x != nil && traversed <= end { 391 next := x.loadNext(0) 392 l.deleteNode(x, &update) 393 delete(dict, x.value) 394 removed = append(removed, Node[K]{ 395 Value: x.value, 396 Score: x.score, 397 }) 398 traversed++ 399 x = next 400 } 401 return removed 402 } 403 404 // GetNodeByRank finds an element by its rank. The rank argument needs to be 1-based. 405 func (l *list[K]) GetNodeByRank(rank int) *listNode[K] { 406 var traversed int 407 408 x := l.header 409 for i := l.highestLevel - 1; i >= 0; i-- { 410 next, span := x.loadNextAndSpan(i) 411 for next != nil && traversed+span <= rank { 412 traversed += span 413 x = next 414 next, span = x.loadNextAndSpan(i) 415 } 416 if traversed == rank { 417 return x 418 } 419 } 420 return nil 421 } 422 423 // FirstInRange finds the first node that is contained in the specified range. 424 func (l *list[K]) FirstInRange(min, max float64, opt RangeOpt) *listNode[K] { 425 if !l.IsInRange(min, max, opt) { 426 return nil 427 } 428 429 x := l.header 430 for i := l.highestLevel - 1; i >= 0; i-- { 431 next := x.loadNext(i) 432 for next != nil && !greaterThanMin(next.score, min, opt.ExcludeMin) { 433 x = next 434 next = x.loadNext(i) 435 } 436 } 437 438 // The next node MUST not be NULL (excluded by IsInRange). 439 x = x.loadNext(0) 440 if !lessThanMax(x.score, max, opt.ExcludeMax) { 441 return nil 442 } 443 return x 444 } 445 446 // LastInRange finds the last node that is contained in the specified range. 447 func (l *list[K]) LastInRange(min, max float64, opt RangeOpt) *listNode[K] { 448 if !l.IsInRange(min, max, opt) { 449 return nil 450 } 451 452 x := l.header 453 for i := l.highestLevel - 1; i >= 0; i-- { 454 next := x.loadNext(i) 455 for next != nil && lessThanMax(next.score, max, opt.ExcludeMax) { 456 x = next 457 next = x.loadNext(i) 458 } 459 } 460 461 // The node x must not be NULL (excluded by IsInRange). 462 if !greaterThanMin(x.score, min, opt.ExcludeMin) { 463 return nil 464 } 465 return x 466 } 467 468 // IsInRange returns whether there is a port of sorted set in given range. 469 func (l *list[K]) IsInRange(min, max float64, opt RangeOpt) bool { 470 // Test empty range. 471 if min > max || (min == max && (opt.ExcludeMin || opt.ExcludeMax)) { 472 return false 473 } 474 if l.tail == nil || !greaterThanMin(l.tail.score, min, opt.ExcludeMin) { 475 return false 476 } 477 if next := l.header.loadNext(0); next == nil || !lessThanMax(next.score, max, opt.ExcludeMax) { 478 return false 479 } 480 return true 481 }