github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/tree/rbtree_test.go (about) 1 package tree 2 3 import ( 4 randv2 "math/rand/v2" 5 "sort" 6 "testing" 7 8 "github.com/benz9527/xboot/lib/id" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestNilNode(t *testing.T) { 13 var nilNode RBNode[uint64, uint64] = nil 14 require.True(t, nilNode == nil) 15 16 var nilNode2 *rbNode[uint64, uint64] = nil 17 nilNode = nilNode2 18 require.True(t, nilNode != nil) 19 require.Nil(t, nilNode) 20 } 21 22 func TestRbtreeLeftAndRightRotate_Pred(t *testing.T) { 23 type checkData struct { 24 color RBColor 25 key uint64 26 } 27 28 tree := &rbTree[uint64, uint64]{ 29 isDesc: false, 30 isRmBorrowSucc: false, 31 } 32 33 tree.Insert(52, 1) 34 expected := []checkData{ 35 {Black, 52}, 36 } 37 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 38 require.Equal(t, expected[idx].color, color) 39 require.Equal(t, expected[idx].key, key) 40 return true 41 }) 42 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 43 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 44 45 tree.Insert(47, 1) 46 expected = []checkData{ 47 {Red, 47}, {Black, 52}, 48 } 49 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 50 require.Equal(t, expected[idx].color, color) 51 require.Equal(t, expected[idx].key, key) 52 return true 53 }) 54 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 55 56 tree.Insert(3, 1) 57 expected = []checkData{ 58 {Red, 3}, {Black, 47}, {Red, 52}, 59 } 60 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 61 require.Equal(t, expected[idx].color, color) 62 require.Equal(t, expected[idx].key, key) 63 return true 64 }) 65 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 66 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 67 68 tree.Insert(35, 1) 69 expected = []checkData{ 70 {Black, 3}, 71 {Red, 35}, 72 {Black, 47}, 73 {Black, 52}, 74 } 75 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 76 require.Equal(t, expected[idx].color, color) 77 require.Equal(t, expected[idx].key, key) 78 return true 79 }) 80 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 81 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 82 83 tree.Insert(24, 1) 84 expected = []checkData{ 85 {Red, 3}, 86 {Black, 24}, 87 {Red, 35}, 88 {Black, 47}, 89 {Black, 52}, 90 } 91 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 92 require.Equal(t, expected[idx].color, color) 93 require.Equal(t, expected[idx].key, key) 94 return true 95 }) 96 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 97 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 98 99 // remove 100 101 x, err := tree.Remove(24) 102 require.NoError(t, err) 103 require.Equal(t, uint64(24), x.Key()) 104 expected = []checkData{ 105 {Black, 3}, 106 {Red, 35}, 107 {Black, 47}, 108 {Black, 52}, 109 } 110 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 111 require.Equal(t, expected[idx].color, color) 112 require.Equal(t, expected[idx].key, key) 113 return true 114 }) 115 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 116 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 117 118 x, err = tree.Remove(47) 119 require.NoError(t, err) 120 require.Equal(t, uint64(47), x.Key()) 121 expected = []checkData{ 122 {Black, 3}, 123 {Black, 35}, 124 {Black, 52}, 125 } 126 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 127 require.Equal(t, expected[idx].color, color) 128 require.Equal(t, expected[idx].key, key) 129 return true 130 }) 131 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 132 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 133 134 x, err = tree.Remove(52) 135 require.NoError(t, err) 136 require.Equal(t, uint64(52), x.Key()) 137 expected = []checkData{ 138 {Red, 3}, {Black, 35}, 139 } 140 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 141 require.Equal(t, expected[idx].color, color) 142 require.Equal(t, expected[idx].key, key) 143 return true 144 }) 145 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 146 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 147 148 x, err = tree.Remove(3) 149 require.NoError(t, err) 150 require.Equal(t, uint64(3), x.Key()) 151 expected = []checkData{ 152 {Black, 35}, 153 } 154 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 155 require.Equal(t, expected[idx].color, color) 156 require.Equal(t, expected[idx].key, key) 157 return true 158 }) 159 require.NoError(t, RedViolationValidate[uint64, uint64](tree)) 160 require.NoError(t, BlackViolationValidate[uint64, uint64](tree)) 161 162 x, err = tree.Remove(35) 163 require.NoError(t, err) 164 require.Equal(t, uint64(35), x.Key()) 165 require.Equal(t, int64(0), tree.Len()) 166 } 167 168 func TestRbtree_RemoveMin(t *testing.T) { 169 type checkData struct { 170 color RBColor 171 key uint64 172 } 173 174 tree := &rbTree[uint64, uint64]{ 175 isDesc: false, 176 isRmBorrowSucc: false, 177 } 178 179 tree.Insert(52, 1) 180 tree.Insert(47, 1) 181 tree.Insert(3, 1) 182 tree.Insert(35, 1) 183 tree.Insert(24, 1) 184 expected := []checkData{ 185 {Red, 3}, 186 {Black, 24}, 187 {Red, 35}, 188 {Black, 47}, 189 {Black, 52}, 190 } 191 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 192 require.Equal(t, expected[idx].color, color) 193 require.Equal(t, expected[idx].key, key) 194 return true 195 }) 196 197 // remove min 198 199 x, err := tree.RemoveMin() 200 require.NoError(t, err) 201 require.Equal(t, uint64(3), x.Key()) 202 expected = []checkData{ 203 {Black, 24}, 204 {Red, 35}, 205 {Black, 47}, 206 {Black, 52}, 207 } 208 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 209 require.Equal(t, expected[idx].color, color) 210 require.Equal(t, expected[idx].key, key) 211 return true 212 }) 213 require.NoError(t, RedViolationValidate(tree)) 214 require.NoError(t, BlackViolationValidate(tree)) 215 216 x, err = tree.RemoveMin() 217 require.NoError(t, err) 218 require.Equal(t, uint64(24), x.Key()) 219 expected = []checkData{ 220 {Black, 35}, 221 {Black, 47}, 222 {Black, 52}, 223 } 224 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 225 require.Equal(t, expected[idx].color, color) 226 require.Equal(t, expected[idx].key, key) 227 return true 228 }) 229 require.NoError(t, RedViolationValidate(tree)) 230 require.NoError(t, BlackViolationValidate(tree)) 231 232 x, err = tree.RemoveMin() 233 require.NoError(t, err) 234 require.Equal(t, uint64(35), x.Key()) 235 expected = []checkData{ 236 {Black, 47}, {Red, 52}, 237 } 238 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 239 require.Equal(t, expected[idx].color, color) 240 require.Equal(t, expected[idx].key, key) 241 return true 242 }) 243 require.NoError(t, RedViolationValidate(tree)) 244 require.NoError(t, BlackViolationValidate(tree)) 245 246 x, err = tree.RemoveMin() 247 require.NoError(t, err) 248 require.Equal(t, uint64(47), x.Key()) 249 expected = []checkData{ 250 {Black, 52}, 251 } 252 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 253 require.Equal(t, expected[idx].color, color) 254 require.Equal(t, expected[idx].key, key) 255 return true 256 }) 257 require.NoError(t, RedViolationValidate(tree)) 258 require.NoError(t, BlackViolationValidate(tree)) 259 260 x, err = tree.RemoveMin() 261 require.NoError(t, err) 262 require.Equal(t, uint64(52), x.Key()) 263 require.Equal(t, int64(0), tree.Len()) 264 } 265 266 func rbtreeRandomInsertAndRemoveSequentialNumberRunCore(t *testing.T, rbRmBySucc bool) { 267 total := uint64(1000) 268 insertTotal := uint64(float64(total) * 0.8) 269 removeTotal := uint64(float64(total) * 0.2) 270 271 tree := &rbTree[uint64, uint64]{ 272 isDesc: false, 273 isRmBorrowSucc: rbRmBySucc, 274 } 275 276 for i := uint64(0); i < insertTotal; i++ { 277 tree.Insert(i, 1) 278 require.NoError(t, RedViolationValidate(tree)) 279 require.NoError(t, BlackViolationValidate(tree)) 280 } 281 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 282 require.Equal(t, uint64(idx), key) 283 return true 284 }) 285 286 for i := insertTotal; i < removeTotal+insertTotal; i++ { 287 tree.Insert(i, 1) 288 require.NoError(t, RedViolationValidate(tree)) 289 require.NoError(t, BlackViolationValidate(tree)) 290 } 291 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 292 require.Equal(t, uint64(idx), key) 293 return true 294 }) 295 296 for i := insertTotal; i < removeTotal+insertTotal; i++ { 297 if i == 92 { 298 x := tree.Search(tree.root, func(node RBNode[uint64, uint64]) int64 { 299 if i == node.Key() { 300 return 0 301 } else if i < node.Key() { 302 return -1 303 } 304 return 1 305 }) 306 require.Equal(t, uint64(92), x.Key()) 307 } 308 x, err := tree.Remove(i) 309 require.NoError(t, err) 310 require.Equal(t, i, x.Key()) 311 require.NoError(t, RedViolationValidate(tree)) 312 require.NoError(t, BlackViolationValidate(tree)) 313 } 314 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 315 require.Equal(t, uint64(idx), key) 316 return true 317 }) 318 } 319 320 func TestRbtreeRandomInsertAndRemove_SequentialNumber(t *testing.T) { 321 type testcase struct { 322 name string 323 rbRmBySucc bool 324 } 325 testcases := []testcase{ 326 { 327 name: "rm by pred", 328 }, 329 { 330 name: "rm by succ", 331 rbRmBySucc: true, 332 }, 333 } 334 for _, tc := range testcases { 335 t.Run(tc.name, func(tt *testing.T) { 336 rbtreeRandomInsertAndRemoveSequentialNumberRunCore(tt, tc.rbRmBySucc) 337 }) 338 } 339 } 340 341 func TestRBTreeRandomInsertAndRemove_SequentialNumber_Release(t *testing.T) { 342 insertTotal := uint64(100_000) 343 344 tree := &rbTree[uint64, uint64]{ 345 isDesc: false, 346 isRmBorrowSucc: false, 347 } 348 349 rand := uint64(randv2.Uint32() % 1_000) 350 for i := uint64(0); i < insertTotal; i++ { 351 tree.Insert(i, 1) 352 if i%1000 == rand { 353 require.NoError(t, RedViolationValidate(tree)) 354 require.NoError(t, BlackViolationValidate(tree)) 355 } 356 } 357 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 358 require.Equal(t, uint64(idx), key) 359 return true 360 }) 361 tree.Release() 362 require.Equal(t, int64(0), tree.Len()) 363 require.Nil(t, tree.Root()) 364 } 365 366 func TestRbtreeRandomInsertAndRemove_ReverseSequentialNumber(t *testing.T) { 367 total := int64(10000) 368 insertTotal := int64(float64(total) * 0.8) 369 removeTotal := int64(float64(total) * 0.2) 370 371 tree := &rbTree[int64, uint64]{ 372 isDesc: true, 373 isRmBorrowSucc: false, 374 } 375 376 rand := int64(randv2.Uint32() % 1_000) 377 for i := insertTotal - 1; i >= 0; i-- { 378 tree.Insert(i, 1) 379 if i%1000 == rand { 380 require.NoError(t, RedViolationValidate(tree)) 381 require.NoError(t, BlackViolationValidate(tree)) 382 } 383 } 384 tree.Foreach(func(idx int64, color RBColor, key int64, val uint64) bool { 385 require.Equal(t, int64(insertTotal-1-idx), key) 386 return true 387 }) 388 389 for i := removeTotal + insertTotal - 1; i >= insertTotal; i-- { 390 tree.Insert(i, 1) 391 } 392 tree.Foreach(func(idx int64, color RBColor, key int64, val uint64) bool { 393 require.Equal(t, int64(removeTotal+insertTotal-1-idx), key) 394 return true 395 }) 396 397 for i := insertTotal; i < removeTotal+insertTotal; i++ { 398 if i == 92 { 399 x := tree.Search(tree.root, func(x RBNode[int64, uint64]) int64 { 400 if i == x.Key() { 401 return 0 402 } else if i < x.Key() { 403 return 1 404 } 405 return -1 406 }) 407 require.Equal(t, int64(92), x.Key()) 408 } 409 x, err := tree.Remove(i) 410 require.NoError(t, err) 411 require.Equal(t, i, x.Key()) 412 } 413 tree.Foreach(func(idx int64, color RBColor, key int64, val uint64) bool { 414 require.Equal(t, int64(insertTotal-1-idx), key) 415 return true 416 }) 417 } 418 419 func rbtreeRandomInsertAndRemove_RandomMonoNumberRunCore(t *testing.T, total uint64, rbRmBySucc bool, violationCheck bool) { 420 insertTotal := uint64(float64(total) * 0.8) 421 removeTotal := uint64(float64(total) * 0.2) 422 423 idGen, _ := id.MonotonicNonZeroID() 424 insertElements := make([]uint64, 0, insertTotal) 425 removeElements := make([]uint64, 0, removeTotal) 426 427 ignore := uint32(0) 428 429 for { 430 num := idGen.Number() 431 if ignore > 0 { 432 ignore-- 433 continue 434 } 435 ignore = randv2.Uint32() % 100 436 if ignore&0x1 == 0 && uint64(len(insertElements)) < insertTotal { 437 insertElements = append(insertElements, num) 438 } else if ignore&0x1 == 1 && uint64(len(removeElements)) < removeTotal { 439 removeElements = append(removeElements, num) 440 } 441 if uint64(len(insertElements)) == insertTotal && uint64(len(removeElements)) == removeTotal { 442 break 443 } 444 } 445 446 shuffle := func(arr []uint64) { 447 count := uint32(len(arr) >> 2) 448 for i := uint32(0); i < count; i++ { 449 j := randv2.Uint32() % (i + 1) 450 arr[i], arr[j] = arr[j], arr[i] 451 } 452 } 453 454 shuffle(insertElements) 455 shuffle(removeElements) 456 457 tree := &rbTree[uint64, uint64]{ 458 isDesc: false, 459 isRmBorrowSucc: rbRmBySucc, 460 } 461 462 for i := uint64(0); i < insertTotal; i++ { 463 tree.Insert(insertElements[i], i) 464 if violationCheck { 465 require.NoError(t, RedViolationValidate(tree)) 466 require.NoError(t, BlackViolationValidate(tree)) 467 } 468 } 469 sort.Slice(insertElements, func(i, j int) bool { 470 return insertElements[i] < insertElements[j] 471 }) 472 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 473 require.Equal(t, insertElements[idx], key) 474 return true 475 }) 476 477 for i := uint64(0); i < removeTotal; i++ { 478 tree.Insert(removeElements[i], 1) 479 if violationCheck { 480 require.NoError(t, RedViolationValidate(tree)) 481 require.NoError(t, BlackViolationValidate(tree)) 482 } 483 } 484 require.NoError(t, RedViolationValidate(tree)) 485 require.NoError(t, BlackViolationValidate(tree)) 486 487 for i := uint64(0); i < removeTotal; i++ { 488 x, err := tree.Remove(removeElements[i]) 489 require.NoError(t, err) 490 require.Equalf(t, removeElements[i], x.Key(), "value exp: %d, real: %d\n", removeElements[i], x.Key()) 491 if violationCheck { 492 require.NoError(t, RedViolationValidate(tree)) 493 require.NoError(t, BlackViolationValidate(tree)) 494 } 495 } 496 tree.Foreach(func(idx int64, color RBColor, key uint64, val uint64) bool { 497 require.Equal(t, insertElements[idx], key) 498 return true 499 }) 500 } 501 502 func TestRbtreeRandomInsertAndRemove_RandomMonotonicNumber(t *testing.T) { 503 type testcase struct { 504 name string 505 rbRmBySucc bool 506 total uint64 507 violationCheck bool 508 } 509 testcases := []testcase{ 510 { 511 name: "rm by pred 1000000", 512 total: 1000000, 513 }, 514 { 515 name: "rm by succ 1000000", 516 rbRmBySucc: true, 517 total: 1000000, 518 }, 519 { 520 name: "violation check rm by pred 10000", 521 total: 10000, 522 violationCheck: true, 523 }, 524 { 525 name: "violation check rm by succ 10000", 526 rbRmBySucc: true, 527 total: 10000, 528 violationCheck: true, 529 }, 530 { 531 name: "violation check rm by pred 20000", 532 total: 20000, 533 violationCheck: true, 534 }, 535 { 536 name: "violation check rm by succ 20000", 537 rbRmBySucc: true, 538 total: 20000, 539 violationCheck: true, 540 }, 541 } 542 t.Parallel() 543 for _, tc := range testcases { 544 t.Run(tc.name, func(tt *testing.T) { 545 rbtreeRandomInsertAndRemove_RandomMonoNumberRunCore(tt, tc.total, tc.rbRmBySucc, tc.violationCheck) 546 }) 547 } 548 } 549 550 func BenchmarkRBTree_Random(b *testing.B) { 551 testByBytes := []byte(`abc`) 552 553 b.StopTimer() 554 tree := NewRBTree[int, []byte]() 555 556 rngArr := make([]int, 0, b.N) 557 for i := 0; i < b.N; i++ { 558 rngArr = append(rngArr, randv2.Int()) 559 } 560 561 b.StartTimer() 562 for i := 0; i < b.N; i++ { 563 err := tree.Insert(rngArr[i], testByBytes) 564 if err != nil { 565 panic(err) 566 } 567 } 568 } 569 570 func BenchmarkRBTree_Serial(b *testing.B) { 571 testByBytes := []byte(`abc`) 572 573 b.StopTimer() 574 tree := NewRBTree[int, []byte]() 575 576 b.StartTimer() 577 for i := 0; i < b.N; i++ { 578 tree.Insert(i, testByBytes) 579 } 580 }