github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/list/x_conc_skl_node_test.go (about) 1 package list 2 3 import ( 4 "cmp" 5 "runtime" 6 "sort" 7 "strconv" 8 "sync" 9 "sync/atomic" 10 "testing" 11 "time" 12 "unsafe" 13 14 "github.com/stretchr/testify/require" 15 16 "github.com/benz9527/xboot/lib/id" 17 "github.com/benz9527/xboot/lib/infra" 18 ) 19 20 // Auxiliary: records the traverse predecessors and successors info. 21 type xConcSklAux[K infra.OrderedKey, V any] []*xConcSklNode[K, V] 22 23 // Left part. 24 func (aux xConcSklAux[K, V]) loadPred(i int32) *xConcSklNode[K, V] { 25 return aux[i] 26 } 27 28 func (aux xConcSklAux[K, V]) storePred(i int32, pred *xConcSklNode[K, V]) { 29 aux[i] = pred 30 } 31 32 func (aux xConcSklAux[K, V]) foreachPred(fn func(list ...*xConcSklNode[K, V])) { 33 fn(aux[0:sklMaxLevel]...) 34 } 35 36 // Right part. 37 func (aux xConcSklAux[K, V]) loadSucc(i int32) *xConcSklNode[K, V] { 38 return aux[sklMaxLevel+i] 39 } 40 41 func (aux xConcSklAux[K, V]) storeSucc(i int32, succ *xConcSklNode[K, V]) { 42 aux[sklMaxLevel+i] = succ 43 } 44 45 func (aux xConcSklAux[K, V]) foreachSucc(fn func(list ...*xConcSklNode[K, V])) { 46 fn(aux[sklMaxLevel:]...) 47 } 48 49 type xConcSklIndex[K infra.OrderedKey, V any] struct { 50 forward *xConcSklNode[K, V] 51 } 52 53 type xConcSklIndices[W infra.OrderedKey, O any] []*xConcSklIndex[W, O] 54 55 func TestXConcSkl_Indexes(t *testing.T) { 56 idx := make(xConcSklIndices[uint8, *xSklObject], 2) 57 idx[0] = &xConcSklIndex[uint8, *xSklObject]{ 58 forward: nil, 59 } 60 idx[0].forward = &xConcSklNode[uint8, *xSklObject]{} 61 idx[0] = &xConcSklIndex[uint8, *xSklObject]{ 62 forward: nil, 63 } 64 ptr := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&idx[0].forward))) 65 t.Logf("%v\n", ptr) 66 } 67 68 func TestDecreaseIndexSize(t *testing.T) { 69 idxSize := uint64(100) 70 atomic.AddUint64(&idxSize, ^uint64(50-1)) 71 require.Equal(t, uint64(50), idxSize) 72 } 73 74 func TestXConcSklNodeSize(t *testing.T) { 75 node := new(xConcSklNode[int64, []byte]) 76 size := unsafe.Sizeof(*node) 77 t.Log(size) 78 } 79 80 type vNode[W SkipListWeight, O HashObject] struct { 81 weight *atomic.Pointer[W] 82 object *atomic.Pointer[O] 83 next *atomic.Pointer[vNode[W, O]] 84 } 85 86 func TestAtomicPointerCAS(t *testing.T) { 87 a := &vNode[uint8, *xSklObject]{ 88 weight: &atomic.Pointer[uint8]{}, 89 object: &atomic.Pointer[*xSklObject]{}, 90 next: nil, 91 } 92 w1 := uint8(1) 93 o1 := &xSklObject{ 94 id: "1", 95 } 96 a.weight.Store(&w1) 97 a.object.Store(&o1) 98 99 b := a 100 101 w2 := uint8(2) 102 o2 := &xSklObject{ 103 id: "2", 104 } 105 c := &vNode[uint8, *xSklObject]{ 106 weight: &atomic.Pointer[uint8]{}, 107 object: &atomic.Pointer[*xSklObject]{}, 108 next: nil, 109 } 110 c.weight.Store(&w2) 111 c.object.Store(&o2) 112 113 ptr := atomic.Pointer[vNode[uint8, *xSklObject]]{} 114 ptr.Store(a) 115 res := ptr.CompareAndSwap(b, c) 116 require.True(t, res) 117 require.Equal(t, c, ptr.Load()) 118 } 119 120 func TestUnsafePointerCAS(t *testing.T) { 121 type obj struct { 122 id int 123 } 124 a := &obj{ 125 id: 1, 126 } 127 b := a 128 c := &obj{ 129 id: 2, 130 } 131 132 res := atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&a)), unsafe.Pointer(b), unsafe.Pointer(c)) 133 require.True(t, res) 134 require.Equal(t, c, a) 135 } 136 137 func TestUnsafePointerCAS_ConcurrentMemVisibility(t *testing.T) { 138 runtime.GOMAXPROCS(4) 139 type obj struct { 140 id string 141 } 142 a := &obj{ 143 id: "1", 144 } 145 b := a 146 c := &obj{ 147 id: "2", 148 } 149 150 logC := make(chan string, 1000) 151 152 var wg sync.WaitGroup 153 wg.Add(4) 154 go func() { 155 for i := 0; i < 200; i++ { 156 val := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&a))) 157 log := "cas load a vptr, obj: " + (*obj)(val).id + ", id: 1" 158 runtime.Gosched() 159 logC <- log 160 } 161 wg.Done() 162 }() 163 go func() { 164 for i := 0; i < 200; i++ { 165 val := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&a))) 166 log := "cas load a vptr, obj: " + (*obj)(val).id + ", id: 2" 167 runtime.Gosched() 168 logC <- log 169 } 170 wg.Done() 171 }() 172 go func() { 173 swapped := false 174 for i := 0; i < 50; i++ { 175 ms := cryptoRandUint32() % 11 176 if ms == 5 && !swapped { 177 log := "starting to cas obj to c, id: 1, loop: " + strconv.Itoa(i) 178 logC <- log 179 swapped = atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&a)), unsafe.Pointer(b), unsafe.Pointer(c)) 180 if swapped != true { 181 log = "cas result is false, id: 1" 182 logC <- log 183 } else { 184 log = "cas result is ok, id: 1" 185 logC <- log 186 } 187 } 188 } 189 wg.Done() 190 }() 191 go func() { 192 swapped := false 193 for i := 0; i < 50; i++ { 194 ms := cryptoRandUint32() % 11 195 if ms == 6 && !swapped { 196 log := "starting to cas obj to c, id: 2, loop: " + strconv.Itoa(i) 197 logC <- log 198 swapped = atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&a)), unsafe.Pointer(b), unsafe.Pointer(c)) 199 if swapped != true { 200 log = "cas result is false, id: 2" 201 logC <- log 202 } else { 203 log = "cas result is ok, id: 2" 204 logC <- log 205 } 206 } 207 } 208 wg.Done() 209 }() 210 go func() { 211 for log := range logC { 212 t.Log(log) 213 } 214 }() 215 wg.Wait() 216 time.Sleep(1 * time.Second) 217 } 218 219 func TestAuxIndexes(t *testing.T) { 220 aux := make(xConcSklAux[uint8, *xSklObject], 2*sklMaxLevel) 221 for i := uint8(0); i < 2*sklMaxLevel; i++ { 222 aux[i] = &xConcSklNode[uint8, *xSklObject]{ 223 key: i, 224 } 225 } 226 227 for i := uint8(0); i < sklMaxLevel; i++ { 228 require.Equal(t, i, aux.loadPred(int32(i)).key) 229 require.Equal(t, sklMaxLevel+i, aux.loadSucc(int32(i)).key) 230 } 231 232 aux.foreachPred(func(predList ...*xConcSklNode[uint8, *xSklObject]) { 233 for i := uint8(0); i < sklMaxLevel; i++ { 234 require.Equal(t, i, predList[i].key) 235 } 236 }) 237 aux.foreachSucc(func(succList ...*xConcSklNode[uint8, *xSklObject]) { 238 for i := uint8(0); i < sklMaxLevel; i++ { 239 require.Equal(t, sklMaxLevel+i, succList[i].key) 240 } 241 }) 242 } 243 244 // test remove by pred references: 245 // https://www.cs.usfca.edu/~galles/visualization/RedBlack.html 246 // https://github.com/minghu6/rust-minghu6/blob/master/coll_st/src/bst/rb.rs 247 248 func TestRbtreeLeftAndRightRotate(t *testing.T) { 249 type checkData struct { 250 color color 251 val uint64 252 } 253 254 vcmp := func(i, j uint64) int64 { 255 if i == j { 256 return 0 257 } else if i > j { 258 return 1 259 } 260 return -1 261 } 262 263 node := &xConcSklNode[uint64, uint64]{} 264 node.rbInsert(52, vcmp) 265 expected := []checkData{ 266 {black, 52}, 267 } 268 node.rbDFS(func(idx int64, color color, val uint64) bool { 269 require.Equal(t, expected[idx].color, color) 270 require.Equal(t, expected[idx].val, val) 271 return true 272 }) 273 require.NoError(t, node.rbRedViolationValidate()) 274 require.NoError(t, node.rbBlackViolationValidate()) 275 276 node.rbInsert(47, vcmp) 277 expected = []checkData{ 278 {red, 47}, {black, 52}, 279 } 280 node.rbDFS(func(idx int64, color color, val uint64) bool { 281 require.Equal(t, expected[idx].color, color) 282 require.Equal(t, expected[idx].val, val) 283 return true 284 }) 285 require.NoError(t, node.rbRedViolationValidate()) 286 287 node.rbInsert(3, vcmp) 288 expected = []checkData{ 289 {red, 3}, {black, 47}, {red, 52}, 290 } 291 node.rbDFS(func(idx int64, color color, val uint64) bool { 292 require.Equal(t, expected[idx].color, color) 293 require.Equal(t, expected[idx].val, val) 294 return true 295 }) 296 require.NoError(t, node.rbRedViolationValidate()) 297 require.NoError(t, node.rbBlackViolationValidate()) 298 299 node.rbInsert(35, vcmp) 300 expected = []checkData{ 301 {black, 3}, 302 {red, 35}, 303 {black, 47}, 304 {black, 52}, 305 } 306 node.rbDFS(func(idx int64, color color, val uint64) bool { 307 require.Equal(t, expected[idx].color, color) 308 require.Equal(t, expected[idx].val, val) 309 return true 310 }) 311 require.NoError(t, node.rbRedViolationValidate()) 312 require.NoError(t, node.rbBlackViolationValidate()) 313 314 node.rbInsert(24, vcmp) 315 expected = []checkData{ 316 {red, 3}, 317 {black, 24}, 318 {red, 35}, 319 {black, 47}, 320 {black, 52}, 321 } 322 node.rbDFS(func(idx int64, color color, val uint64) bool { 323 require.Equal(t, expected[idx].color, color) 324 require.Equal(t, expected[idx].val, val) 325 return true 326 }) 327 require.NoError(t, node.rbRedViolationValidate()) 328 require.NoError(t, node.rbBlackViolationValidate()) 329 330 // remove 331 332 x, err := node.rbRemove(24, vcmp) 333 require.NoError(t, err) 334 require.Equal(t, uint64(24), *x.vptr) 335 expected = []checkData{ 336 {black, 3}, 337 {red, 35}, 338 {black, 47}, 339 {black, 52}, 340 } 341 node.rbDFS(func(idx int64, color color, val uint64) bool { 342 require.Equal(t, expected[idx].color, color) 343 require.Equal(t, expected[idx].val, val) 344 return true 345 }) 346 require.NoError(t, node.rbRedViolationValidate()) 347 require.NoError(t, node.rbBlackViolationValidate()) 348 349 x, err = node.rbRemove(47, vcmp) 350 require.NoError(t, err) 351 require.Equal(t, uint64(47), *x.vptr) 352 expected = []checkData{ 353 {black, 3}, 354 {black, 35}, 355 {black, 52}, 356 } 357 node.rbDFS(func(idx int64, color color, val uint64) bool { 358 require.Equal(t, expected[idx].color, color) 359 require.Equal(t, expected[idx].val, val) 360 return true 361 }) 362 require.NoError(t, node.rbRedViolationValidate()) 363 require.NoError(t, node.rbBlackViolationValidate()) 364 365 x, err = node.rbRemove(52, vcmp) 366 require.NoError(t, err) 367 require.Equal(t, uint64(52), *x.vptr) 368 expected = []checkData{ 369 {red, 3}, {black, 35}, 370 } 371 node.rbDFS(func(idx int64, color color, val uint64) bool { 372 require.Equal(t, expected[idx].color, color) 373 require.Equal(t, expected[idx].val, val) 374 return true 375 }) 376 require.NoError(t, node.rbRedViolationValidate()) 377 require.NoError(t, node.rbBlackViolationValidate()) 378 379 x, err = node.rbRemove(3, vcmp) 380 require.NoError(t, err) 381 require.Equal(t, uint64(3), *x.vptr) 382 expected = []checkData{ 383 {black, 35}, 384 } 385 node.rbDFS(func(idx int64, color color, val uint64) bool { 386 require.Equal(t, expected[idx].color, color) 387 require.Equal(t, expected[idx].val, val) 388 return true 389 }) 390 require.NoError(t, node.rbRedViolationValidate()) 391 require.NoError(t, node.rbBlackViolationValidate()) 392 393 x, err = node.rbRemove(35, vcmp) 394 require.NoError(t, err) 395 require.Equal(t, uint64(35), *x.vptr) 396 require.Equal(t, int64(0), atomic.LoadInt64(&node.count)) 397 } 398 399 func TestRbtree_RemoveMin(t *testing.T) { 400 type checkData struct { 401 color color 402 val uint64 403 } 404 405 vcmp := func(i, j uint64) int64 { 406 if i == j { 407 return 0 408 } else if i > j { 409 return 1 410 } 411 return -1 412 } 413 414 node := &xConcSklNode[uint64, uint64]{} 415 node.rbInsert(52, vcmp) 416 node.rbInsert(47, vcmp) 417 node.rbInsert(3, vcmp) 418 node.rbInsert(35, vcmp) 419 node.rbInsert(24, vcmp) 420 expected := []checkData{ 421 {red, 3}, 422 {black, 24}, 423 {red, 35}, 424 {black, 47}, 425 {black, 52}, 426 } 427 node.rbDFS(func(idx int64, color color, val uint64) bool { 428 require.Equal(t, expected[idx].color, color) 429 require.Equal(t, expected[idx].val, val) 430 return true 431 }) 432 433 // remove min 434 435 x, err := node.rbRemoveMin() 436 require.NoError(t, err) 437 require.Equal(t, uint64(3), *x.vptr) 438 expected = []checkData{ 439 {black, 24}, 440 {red, 35}, 441 {black, 47}, 442 {black, 52}, 443 } 444 node.rbDFS(func(idx int64, color color, val uint64) bool { 445 require.Equal(t, expected[idx].color, color) 446 require.Equal(t, expected[idx].val, val) 447 return true 448 }) 449 require.NoError(t, node.rbRedViolationValidate()) 450 require.NoError(t, node.rbBlackViolationValidate()) 451 452 x, err = node.rbRemoveMin() 453 require.NoError(t, err) 454 require.Equal(t, uint64(24), *x.vptr) 455 expected = []checkData{ 456 {black, 35}, 457 {black, 47}, 458 {black, 52}, 459 } 460 node.rbDFS(func(idx int64, color color, val uint64) bool { 461 require.Equal(t, expected[idx].color, color) 462 require.Equal(t, expected[idx].val, val) 463 return true 464 }) 465 require.NoError(t, node.rbRedViolationValidate()) 466 require.NoError(t, node.rbBlackViolationValidate()) 467 468 x, err = node.rbRemoveMin() 469 require.NoError(t, err) 470 require.Equal(t, uint64(35), *x.vptr) 471 expected = []checkData{ 472 {black, 47}, {red, 52}, 473 } 474 node.rbDFS(func(idx int64, color color, val uint64) bool { 475 require.Equal(t, expected[idx].color, color) 476 require.Equal(t, expected[idx].val, val) 477 return true 478 }) 479 require.NoError(t, node.rbRedViolationValidate()) 480 require.NoError(t, node.rbBlackViolationValidate()) 481 482 x, err = node.rbRemoveMin() 483 require.NoError(t, err) 484 require.Equal(t, uint64(47), *x.vptr) 485 expected = []checkData{ 486 {black, 52}, 487 } 488 node.rbDFS(func(idx int64, color color, val uint64) bool { 489 require.Equal(t, expected[idx].color, color) 490 require.Equal(t, expected[idx].val, val) 491 return true 492 }) 493 require.NoError(t, node.rbRedViolationValidate()) 494 require.NoError(t, node.rbBlackViolationValidate()) 495 496 x, err = node.rbRemoveMin() 497 require.NoError(t, err) 498 require.Equal(t, uint64(52), *x.vptr) 499 require.Equal(t, int64(0), atomic.LoadInt64(&node.count)) 500 } 501 502 func xConcSklNodeRandomInsertAndRemoveRbtreeSequentialNumberRunCore(t *testing.T, rbRmBySucc bool) { 503 total := uint64(1000) 504 insertTotal := uint64(float64(total) * 0.8) 505 removeTotal := uint64(float64(total) * 0.2) 506 507 vcmp := func(i, j uint64) int64 { 508 if i == j { 509 return 0 510 } else if i > j { 511 return 1 512 } 513 return -1 514 } 515 516 node := &xConcSklNode[uint64, uint64]{} 517 if rbRmBySucc { 518 node.flags = set(node.flags, nodeRbRmBorrowFlagBit) 519 } 520 521 for i := uint64(0); i < insertTotal; i++ { 522 node.rbInsert(i, vcmp) 523 require.NoError(t, node.rbRedViolationValidate()) 524 require.NoError(t, node.rbBlackViolationValidate()) 525 } 526 node.rbDFS(func(idx int64, color color, val uint64) bool { 527 require.Equal(t, uint64(idx), val) 528 return true 529 }) 530 531 for i := insertTotal; i < removeTotal+insertTotal; i++ { 532 node.rbInsert(i, vcmp) 533 require.NoError(t, node.rbRedViolationValidate()) 534 require.NoError(t, node.rbBlackViolationValidate()) 535 } 536 node.rbDFS(func(idx int64, color color, val uint64) bool { 537 require.Equal(t, uint64(idx), val) 538 return true 539 }) 540 541 for i := insertTotal; i < removeTotal+insertTotal; i++ { 542 if i == 92 { 543 x := node.rbSearch(node.root, func(x *xNode[uint64]) int64 { 544 return vcmp(i, *x.vptr) 545 }) 546 require.Equal(t, uint64(92), *x.vptr) 547 } 548 x, err := node.rbRemove(i, vcmp) 549 require.NoError(t, err) 550 require.Equal(t, i, *x.vptr) 551 require.NoError(t, node.rbRedViolationValidate()) 552 require.NoError(t, node.rbBlackViolationValidate()) 553 } 554 node.rbDFS(func(idx int64, color color, val uint64) bool { 555 require.Equal(t, uint64(idx), val) 556 return true 557 }) 558 } 559 560 func TestRandomInsertAndRemoveRbtree_SequentialNumber(t *testing.T) { 561 type testcase struct { 562 name string 563 rbRmBySucc bool 564 } 565 testcases := []testcase{ 566 { 567 name: "rm by pred", 568 }, 569 { 570 name: "rm by succ", 571 rbRmBySucc: true, 572 }, 573 } 574 for _, tc := range testcases { 575 t.Run(tc.name, func(tt *testing.T) { 576 xConcSklNodeRandomInsertAndRemoveRbtreeSequentialNumberRunCore(tt, tc.rbRmBySucc) 577 }) 578 } 579 } 580 581 func TestRandomInsertAndRemoveRbtree_SequentialNumber_Release(t *testing.T) { 582 insertTotal := uint64(100000) 583 584 vcmp := func(i, j uint64) int64 { 585 if i == j { 586 return 0 587 } else if i > j { 588 return 1 589 } 590 return -1 591 } 592 593 node := &xConcSklNode[uint64, uint64]{} 594 595 rand := uint64(cryptoRandUint32() % 1000) 596 for i := uint64(0); i < insertTotal; i++ { 597 node.rbInsert(i, vcmp) 598 if i%1000 == rand { 599 require.NoError(t, node.rbRedViolationValidate()) 600 require.NoError(t, node.rbBlackViolationValidate()) 601 } 602 } 603 node.rbDFS(func(idx int64, color color, val uint64) bool { 604 require.Equal(t, uint64(idx), val) 605 return true 606 }) 607 node.rbRelease() 608 require.Equal(t, int64(0), node.count) 609 require.Nil(t, node.root) 610 } 611 612 func TestRandomInsertAndRemoveRbtree_ReverseSequentialNumber(t *testing.T) { 613 total := int64(10000) 614 insertTotal := int64(float64(total) * 0.8) 615 removeTotal := int64(float64(total) * 0.2) 616 617 vcmp := func(i, j int64) int64 { 618 if i == j { 619 return 0 620 } else if i > j { 621 return 1 622 } 623 return -1 624 } 625 626 node := &xConcSklNode[uint64, int64]{} 627 628 rand := int64(cryptoRandUint32() % 1000) 629 for i := insertTotal - 1; i >= 0; i-- { 630 node.rbInsert(i, vcmp) 631 if i%1000 == rand { 632 require.NoError(t, node.rbRedViolationValidate()) 633 require.NoError(t, node.rbBlackViolationValidate()) 634 } 635 } 636 node.rbDFS(func(idx int64, color color, val int64) bool { 637 require.Equal(t, int64(idx), val) 638 return true 639 }) 640 641 for i := removeTotal + insertTotal - 1; i >= insertTotal; i-- { 642 node.rbInsert(i, vcmp) 643 } 644 node.rbDFS(func(idx int64, color color, val int64) bool { 645 require.Equal(t, int64(idx), val) 646 return true 647 }) 648 649 for i := insertTotal; i < removeTotal+insertTotal; i++ { 650 if i == 92 { 651 x := node.rbSearch(node.root, func(x *xNode[int64]) int64 { 652 return vcmp(i, *x.vptr) 653 }) 654 require.Equal(t, int64(92), *x.vptr) 655 } 656 x, err := node.rbRemove(i, vcmp) 657 require.NoError(t, err) 658 require.Equal(t, i, *x.vptr) 659 } 660 node.rbDFS(func(idx int64, color color, val int64) bool { 661 require.Equal(t, int64(idx), val) 662 return true 663 }) 664 } 665 666 func xConcSklNodeRandomInsertAndRemoveRbtreeRandomMonoNumberRunCore(t *testing.T, total uint64, rbRmBySucc bool, violationCheck bool) { 667 insertTotal := uint64(float64(total) * 0.8) 668 removeTotal := uint64(float64(total) * 0.2) 669 670 idGen, _ := id.MonotonicNonZeroID() 671 insertElements := make([]uint64, 0, insertTotal) 672 removeElements := make([]uint64, 0, removeTotal) 673 674 ignore := uint32(0) 675 for { 676 num := idGen.Number() 677 if ignore > 0 { 678 ignore-- 679 continue 680 } 681 ignore = cryptoRandUint32() % 100 682 if ignore&0x1 == 0 && uint64(len(insertElements)) < insertTotal { 683 insertElements = append(insertElements, num) 684 } else if ignore&0x1 == 1 && uint64(len(removeElements)) < removeTotal { 685 removeElements = append(removeElements, num) 686 } 687 if uint64(len(insertElements)) == insertTotal && uint64(len(removeElements)) == removeTotal { 688 break 689 } 690 } 691 692 shuffle := func(arr []uint64) { 693 count := uint32(len(arr) >> 2) 694 for i := uint32(0); i < count; i++ { 695 j := cryptoRandUint32() % (i + 1) 696 arr[i], arr[j] = arr[j], arr[i] 697 } 698 } 699 700 shuffle(insertElements) 701 shuffle(removeElements) 702 703 vcmp := func(i, j uint64) int64 { 704 if i == j { 705 return 0 706 } else if i > j { 707 return 1 708 } 709 return -1 710 } 711 712 node := &xConcSklNode[uint64, uint64]{} 713 if rbRmBySucc { 714 set(node.flags, nodeRbRmBorrowFlagBit) 715 } 716 717 for i := uint64(0); i < insertTotal; i++ { 718 node.rbInsert(insertElements[i], vcmp) 719 if violationCheck { 720 require.NoError(t, node.rbRedViolationValidate()) 721 require.NoError(t, node.rbBlackViolationValidate()) 722 } 723 } 724 sort.Slice(insertElements, func(i, j int) bool { 725 return insertElements[i] < insertElements[j] 726 }) 727 node.rbDFS(func(idx int64, color color, val uint64) bool { 728 require.Equal(t, insertElements[idx], val) 729 return true 730 }) 731 732 for i := uint64(0); i < removeTotal; i++ { 733 node.rbInsert(removeElements[i], vcmp) 734 if violationCheck { 735 require.NoError(t, node.rbRedViolationValidate()) 736 require.NoError(t, node.rbBlackViolationValidate()) 737 } 738 } 739 require.NoError(t, node.rbRedViolationValidate()) 740 require.NoError(t, node.rbBlackViolationValidate()) 741 742 for i := uint64(0); i < removeTotal; i++ { 743 x, err := node.rbRemove(removeElements[i], vcmp) 744 require.NoError(t, err) 745 require.Equalf(t, removeElements[i], *x.vptr, "value exp: %d, real: %d\n", removeElements[i], *x.vptr) 746 if violationCheck { 747 require.NoError(t, node.rbRedViolationValidate()) 748 require.NoError(t, node.rbBlackViolationValidate()) 749 } 750 } 751 node.rbDFS(func(idx int64, color color, val uint64) bool { 752 require.Equal(t, insertElements[idx], val) 753 return true 754 }) 755 } 756 757 func TestRandomInsertAndRemoveRbtree_RandomMonotonicNumber(t *testing.T) { 758 type testcase struct { 759 name string 760 rbRmBySucc bool 761 total uint64 762 violationCheck bool 763 } 764 testcases := []testcase{ 765 { 766 name: "rm by pred 1000000", 767 total: 1000000, 768 }, 769 { 770 name: "rm by succ 1000000", 771 rbRmBySucc: true, 772 total: 1000000, 773 }, 774 { 775 name: "violation check rm by pred 10000", 776 total: 10000, 777 violationCheck: true, 778 }, 779 { 780 name: "violation check rm by succ 10000", 781 rbRmBySucc: true, 782 total: 10000, 783 violationCheck: true, 784 }, 785 { 786 name: "violation check rm by pred 20000", 787 total: 20000, 788 violationCheck: true, 789 }, 790 { 791 name: "violation check rm by succ 20000", 792 rbRmBySucc: true, 793 total: 20000, 794 violationCheck: true, 795 }, 796 } 797 t.Parallel() 798 for _, tc := range testcases { 799 t.Run(tc.name, func(tt *testing.T) { 800 xConcSklNodeRandomInsertAndRemoveRbtreeRandomMonoNumberRunCore(tt, tc.total, tc.rbRmBySucc, tc.violationCheck) 801 }) 802 } 803 } 804 805 func TestXConcSklNodeGen(t *testing.T) { 806 for lvl := int32(1); lvl <= sklMaxLevel; lvl++ { 807 genXConcSklUniqueNode[string, int]("123", 1, lvl) 808 } 809 require.Panics(t, func() { 810 genXConcSklUniqueNode[string, int]("123", 1, 0) 811 }) 812 813 for lvl := int32(1); lvl <= sklMaxLevel; lvl++ { 814 genXConcSklLinkedListNode[string, int]("123", 1, lvl) 815 } 816 require.Panics(t, func() { 817 genXConcSklLinkedListNode[string, int]("123", 1, 0) 818 }) 819 820 vcmp := func(i, j int) int64 { 821 return int64(cmp.Compare[int](i, j)) 822 } 823 for lvl := int32(1); lvl <= sklMaxLevel; lvl++ { 824 genXConcSklRbtreeNode[string, int]("123", 1, vcmp, lvl) 825 } 826 require.Panics(t, func() { 827 genXConcSklRbtreeNode[string, int]("123", 1, vcmp, 0) 828 }) 829 }