Changeset 93684 in vbox for trunk/include/iprt/cpp
- Timestamp:
- Feb 11, 2022 1:23:40 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/cpp/hardavlrange.h
r93672 r93684 37 37 38 38 /** 39 * Check that the tree heights make sense for the current node. 40 * 41 * This is a RT_STRICT test as it's expensive and we should have sufficient 42 * other checks to ensure safe AVL tree operation. 43 * 44 * @note the a_cStackEntries parameter is a hack to avoid running into gcc's 45 * "the address of AVLStack will never be NULL" errors. 46 */ 47 #ifdef RT_STRICT 48 # define RTHARDAVL_STRICT_CHECK_HEIGHTS(a_pNode, a_pAvlStack, a_cStackEntries) do { \ 49 NodeType * const pLeftNodeX = a_pAllocator->ptrFromInt((a_pNode)->idxLeft); \ 50 AssertReturnStmt(a_pAllocator->isPtrRetOkay(pLeftNodeX), m_cErrors++, a_pAllocator->ptrErrToStatus((a_pNode))); \ 51 NodeType * const pRightNodeX = a_pAllocator->ptrFromInt((a_pNode)->idxRight); \ 52 AssertReturnStmt(a_pAllocator->isPtrRetOkay(pRightNodeX), m_cErrors++, a_pAllocator->ptrErrToStatus((a_pNode))); \ 53 uint8_t const cLeftHeightX = pLeftNodeX ? pLeftNodeX->cHeight : 0; \ 54 uint8_t const cRightHeightX = pRightNodeX ? pRightNodeX->cHeight : 0; \ 55 if (RT_LIKELY((a_pNode)->cHeight == RT_MAX(cLeftHeightX, cRightHeightX) + 1)) { /*likely*/ } \ 56 else \ 57 { \ 58 RTAssertMsg2("line %u: %u l=%u r=%u\n", __LINE__, (a_pNode)->cHeight, cLeftHeightX, cRightHeightX); \ 59 if ((a_cStackEntries)) dumpStack(a_pAllocator, (a_pAvlStack)); \ 60 AssertMsgReturnStmt((a_pNode)->cHeight == RT_MAX(cLeftHeightX, cRightHeightX) + 1, \ 61 ("%u l=%u r=%u\n", (a_pNode)->cHeight, cLeftHeightX, cRightHeightX), \ 62 m_cErrors++, VERR_HARDAVL_BAD_HEIGHT); \ 63 } \ 64 AssertMsgReturnStmt(RT_ABS(cLeftHeightX - cRightHeightX) <= 1, ("l=%u r=%u\n", cLeftHeightX, cRightHeightX), \ 65 m_cErrors++, VERR_HARDAVL_UNBALANCED); \ 66 Assert(!pLeftNodeX || pLeftNodeX->Key < (a_pNode)->Key); \ 67 Assert(!pRightNodeX || pRightNodeX->Key > (a_pNode)->Key); \ 68 } while (0) 69 #else 70 # define RTHARDAVL_STRICT_CHECK_HEIGHTS(a_pNode, a_pAvlStack, a_cStackEntries) do { } while (0) 71 #endif 72 73 74 /** 39 75 * Hardened AVL tree for nodes with key ranges. 40 76 * … … 152 188 AVLStack.cEntries = cEntries + 1; 153 189 190 RTHARDAVL_STRICT_CHECK_HEIGHTS(pCurNode, &AVLStack, AVLStack.cEntries); 191 154 192 /* Range check: */ 155 193 if (areKeyRangesIntersecting(pCurNode->Key, Key, pCurNode->KeyLast, KeyLast)) … … 174 212 return i_rebalance(a_pAllocator, &AVLStack); 175 213 } 214 215 #ifdef RT_STRICT 216 217 static void dumpStack(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, HardAvlStack const *pStack) 218 { 219 uint32_t const * const *paidx = pStack->apidxEntries; 220 RTAssertMsg2("stack: %u:\n", pStack->cEntries); 221 for (unsigned i = 0; i < pStack->cEntries; i++) 222 { 223 uint32_t idx = *paidx[i]; 224 uint32_t idxNext = i + 1 < pStack->cEntries ? *paidx[i + 1] : UINT32_MAX; 225 NodeType const *pNode = a_pAllocator->ptrFromInt(idx); 226 RTAssertMsg2(" #%02u: %p[%#06x] pNode=%p h=%02d l=%#06x%c r=%#06x%c\n", i, paidx[i], idx, pNode, pNode->cHeight, 227 pNode->idxLeft, pNode->idxLeft == idxNext ? '*' : ' ', 228 pNode->idxRight, pNode->idxRight == idxNext ? '*' : ' '); 229 } 230 } 231 232 static void printTree(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, uint32_t a_idxRoot, unsigned iLevel = 0) 233 { 234 if (a_idxRoot == a_pAllocator->kNilIndex) 235 RTAssertMsg2("%*snil\n", iLevel * 6, ""); 236 else if (iLevel < 7) 237 { 238 NodeType *pNode = a_pAllocator->ptrFromInt(a_idxRoot); 239 printTree(a_pAllocator, pNode->idxRight, iLevel + 1); 240 RTAssertMsg2("%*s%#x/%u\n", iLevel * 6, "", a_idxRoot, pNode->cHeight); 241 printTree(a_pAllocator, pNode->idxLeft, iLevel + 1); 242 } 243 else 244 RTAssertMsg2("%*stoo deep\n", iLevel * 6, ""); 245 } 246 247 #endif 176 248 177 249 /** … … 255 327 AVLStack.cEntries = cEntries + 1; 256 328 329 RTHARDAVL_STRICT_CHECK_HEIGHTS(pDeleteNode, &AVLStack, AVLStack.cEntries); 330 257 331 /* Range check: */ 258 332 if (isKeyInRange(a_Key, pDeleteNode->Key, pDeleteNode->KeyLast)) … … 269 343 * Do the deletion. 270 344 */ 271 if (pDeleteNode->idxLeft != a_pAllocator->kNilIndex) 345 uint32_t const idxDeleteLeftNode = pDeleteNode->idxLeft; 346 if (idxDeleteLeftNode != a_pAllocator->kNilIndex) 272 347 { 273 /* find the rightmost node in the left tree. */ 274 const unsigned iStackEntry = AVLStack.cEntries; 275 uint32_t *pidxLeftLeast = &pDeleteNode->idxLeft; 276 uint32_t idxLeftLeastNode = pDeleteNode->idxLeft; 277 NodeType *pLeftLeastNode = a_pAllocator->ptrFromInt(idxLeftLeastNode); 278 AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftLeastNode), 279 ("idxLeftLeastNode=%#x pLeftLeastNode=%p\n", idxLeftLeastNode, pLeftLeastNode), 280 m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftLeastNode)); 281 282 while (pLeftLeastNode->idxRight != a_pAllocator->kNilIndex) 348 /* 349 * Replace the deleted node with the rightmost node in the left subtree. 350 */ 351 NodeType * const pDeleteLeftNode = a_pAllocator->ptrFromInt(idxDeleteLeftNode); 352 AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pDeleteLeftNode), 353 ("idxDeleteLeftNode=%#x pDeleteLeftNode=%p\n", idxDeleteLeftNode, pDeleteLeftNode), 354 m_cErrors++, a_pAllocator->ptrErrToStatus(pDeleteLeftNode)); 355 356 uint32_t const idxDeleteRightNode = pDeleteNode->idxRight; 357 AssertReturnStmt(a_pAllocator->isIntValid(idxDeleteRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); 358 359 const unsigned iStackEntry = AVLStack.cEntries; 360 361 uint32_t *pidxLeftBiggest = &pDeleteNode->idxLeft; 362 uint32_t idxLeftBiggestNode = idxDeleteLeftNode; 363 NodeType *pLeftBiggestNode = pDeleteLeftNode; 364 RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftBiggestNode, &AVLStack, AVLStack.cEntries); 365 366 while (pLeftBiggestNode->idxRight != a_pAllocator->kNilIndex) 283 367 { 284 368 unsigned const cEntries = AVLStack.cEntries; 285 369 AssertMsgReturnStmt(cEntries < RT_ELEMENTS(AVLStack.apidxEntries), 286 370 ("%p[%#x/%p] %p[%#x] %p[%#x] %p[%#x] %p[%#x] %p[%#x]\n", 287 pidx DeleteNode, *pidxDeleteNode, pDeleteNode,371 pidxLeftBiggest, *pidxLeftBiggest, pLeftBiggestNode, 288 372 AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 1], 289 373 AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 2], … … 292 376 AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5], *AVLStack.apidxEntries[RT_ELEMENTS(AVLStack.apidxEntries) - 5]), 293 377 m_cErrors++, VERR_HARDAVL_STACK_OVERFLOW); 294 AVLStack.apidxEntries[cEntries] = pidxLeft Least;378 AVLStack.apidxEntries[cEntries] = pidxLeftBiggest; 295 379 AVLStack.cEntries = cEntries + 1; 296 380 297 pidxLeftLeast = &pLeftLeastNode->idxRight; 298 idxLeftLeastNode = pLeftLeastNode->idxRight; 299 pLeftLeastNode = a_pAllocator->ptrFromInt(idxLeftLeastNode); 300 AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftLeastNode), 301 ("idxLeftLeastNode=%#x pLeftLeastNode=%p\n", idxLeftLeastNode, pLeftLeastNode), 302 m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftLeastNode)); 381 pidxLeftBiggest = &pLeftBiggestNode->idxRight; 382 idxLeftBiggestNode = pLeftBiggestNode->idxRight; 383 pLeftBiggestNode = a_pAllocator->ptrFromInt(idxLeftBiggestNode); 384 AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pLeftBiggestNode), 385 ("idxLeftBiggestNode=%#x pLeftBiggestNode=%p\n", idxLeftBiggestNode, pLeftBiggestNode), 386 m_cErrors++, a_pAllocator->ptrErrToStatus(pLeftBiggestNode)); 387 RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftBiggestNode, &AVLStack, AVLStack.cEntries); 303 388 } 304 389 305 uint32_t const idxLeftLeastLeftNode = pLeftLeastNode->idxLeft; 306 AssertReturnStmt(a_pAllocator->isIntValid(idxLeftLeastLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); 307 308 uint32_t const idxDeleteLeftNode = pDeleteNode->idxLeft; 309 AssertReturnStmt(a_pAllocator->isIntValid(idxDeleteLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); 310 uint32_t const idxDeleteRightNode = pDeleteNode->idxRight; 311 AssertReturnStmt(a_pAllocator->isIntValid(idxDeleteRightNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); 312 313 /* link out pLeftLeast */ 314 *pidxLeftLeast = idxLeftLeastLeftNode; 315 316 /* link it in place of the delete node. */ 317 pLeftLeastNode->idxLeft = idxDeleteLeftNode; 318 pLeftLeastNode->idxRight = idxDeleteRightNode; 319 pLeftLeastNode->cHeight = pDeleteNode->cHeight; 320 *pidxDeleteNode = idxLeftLeastNode; 321 AVLStack.apidxEntries[iStackEntry] = &pLeftLeastNode->idxLeft; 390 uint32_t const idxLeftBiggestLeftNode = pLeftBiggestNode->idxLeft; 391 AssertReturnStmt(a_pAllocator->isIntValid(idxLeftBiggestLeftNode), m_cErrors++, VERR_HARDAVL_INDEX_OUT_OF_BOUNDS); 392 393 /* link out pLeftBiggestNode */ 394 *pidxLeftBiggest = idxLeftBiggestLeftNode; 395 396 /* link it in place of the deleted node. */ 397 if (idxDeleteLeftNode != idxLeftBiggestNode) 398 pLeftBiggestNode->idxLeft = idxDeleteLeftNode; 399 pLeftBiggestNode->idxRight = idxDeleteRightNode; 400 pLeftBiggestNode->cHeight = AVLStack.cEntries > iStackEntry ? pDeleteNode->cHeight : 0; 401 402 *pidxDeleteNode = idxLeftBiggestNode; 403 404 if (AVLStack.cEntries > iStackEntry) 405 AVLStack.apidxEntries[iStackEntry] = &pLeftBiggestNode->idxLeft; 322 406 } 323 407 else … … 351 435 AssertMsgReturnStmt(a_pAllocator->isPtrRetOkay(pNode), ("m_idxRoot=%#x pNode=%p\n", m_idxRoot, pNode), 352 436 m_cErrors++, a_pAllocator->ptrErrToStatus(pNode)); 353 437 #ifdef RT_STRICT 438 HardAvlStack AVLStack; 439 AVLStack.apidxEntries[0] = &m_idxRoot; 440 AVLStack.cEntries = 1; 441 #endif 354 442 unsigned cDepth = 0; 355 443 while (pNode) 356 444 { 445 RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, &AVLStack, AVLStack.cEntries); 357 446 AssertReturn(cDepth <= kMaxHeight, VERR_HARDAVL_LOOKUP_TOO_DEEP); 358 447 cDepth++; … … 365 454 if (isKeyGreater(pNode->Key, a_Key)) 366 455 { 456 #ifdef RT_STRICT 457 AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxLeft; 458 #endif 367 459 uint32_t const idxLeft = pNode->idxLeft; 368 460 pNode = a_pAllocator->ptrFromInt(idxLeft); … … 372 464 else 373 465 { 466 #ifdef RT_STRICT 467 AVLStack.apidxEntries[AVLStack.cEntries++] = &pNode->idxRight; 468 #endif 374 469 uint32_t const idxRight = pNode->idxRight; 375 470 pNode = a_pAllocator->ptrFromInt(idxRight); … … 461 556 abState[cEntries - 1] = 2; 462 557 558 RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); 559 463 560 int rc = a_pfnCallBack(pNode, a_pvUser); 464 561 if (rc != VINF_SUCCESS) … … 684 781 * @internal 685 782 */ 686 int i_rebalance(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, HardAvlStack *a_pStack) 687 { 783 int i_rebalance(RTCHardAvlTreeSlabAllocator<NodeType> *a_pAllocator, HardAvlStack *a_pStack, bool fLog = false) 784 { 785 RT_NOREF(fLog); 786 688 787 while (a_pStack->cEntries > 0) 689 788 { … … 718 817 if (cRightHeight + 1 < cLeftHeight) 719 818 { 819 Assert(cRightHeight + 2 == cLeftHeight); 720 820 AssertReturnStmt(pLeftNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_LEFT); 721 821 … … 741 841 pLeftNode->idxRight = idxNode; 742 842 *pidxNode = idxLeftNode; 843 #ifdef DEBUG 844 if (fLog) RTAssertMsg2("rebalance: %#2u: op #1\n", a_pStack->cEntries); 845 #endif 743 846 } 744 847 else … … 760 863 pLeftRightNode->cHeight = cLeftHeight; 761 864 *pidxNode = idxLeftRightNode; 865 #ifdef DEBUG 866 if (fLog) RTAssertMsg2("rebalance: %#2u: op #2\n", a_pStack->cEntries); 867 #endif 762 868 } 763 869 } 764 870 else if (cLeftHeight + 1 < cRightHeight) 765 871 { 872 Assert(cLeftHeight + 2 == cRightHeight); 766 873 AssertReturnStmt(pRightNode, m_cErrors++, VERR_HARDAVL_UNEXPECTED_NULL_RIGHT); 767 874 … … 788 895 pRightNode->cHeight = (uint8_t)(cRightLeftHeight + 2); 789 896 *pidxNode = idxRightNode; 897 #ifdef DEBUG 898 if (fLog) RTAssertMsg2("rebalance: %#2u: op #3 h=%d, *pidxNode=%#x\n", a_pStack->cEntries, pRightNode->cHeight, *pidxNode); 899 #endif 900 RTHARDAVL_STRICT_CHECK_HEIGHTS(pRightNode, NULL, 0); 901 RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); 790 902 } 791 903 else … … 800 912 pRightNode->idxLeft = idxRightLeftRightNode; 801 913 pNode->idxRight = idxRightLeftLeftNode; 914 802 915 pRightLeftNode->idxRight = idxRightNode; 803 916 pRightLeftNode->idxLeft = idxNode; … … 806 919 pRightLeftNode->cHeight = cRightHeight; 807 920 *pidxNode = idxRightLeftNode; 921 #ifdef DEBUG 922 if (fLog) RTAssertMsg2("rebalance: %#2u: op #4 h=%d, *pidxNode=%#x\n", a_pStack->cEntries, pRightLeftNode->cHeight, *pidxNode); 923 #endif 808 924 } 809 925 } … … 813 929 AssertReturnStmt(cHeight <= kMaxHeight, m_cErrors++, VERR_HARDAVL_BAD_NEW_HEIGHT); 814 930 if (cHeight == pNode->cHeight) 931 { 932 #ifdef DEBUG 933 if (fLog) RTAssertMsg2("rebalance: %#2u: op #5, h=%d - done\n", a_pStack->cEntries, cHeight); 934 #endif 935 RTHARDAVL_STRICT_CHECK_HEIGHTS(pNode, NULL, 0); 936 if (pLeftNode) 937 RTHARDAVL_STRICT_CHECK_HEIGHTS(pLeftNode, NULL, 0); 938 if (pRightNode) 939 RTHARDAVL_STRICT_CHECK_HEIGHTS(pRightNode, NULL, 0); 815 940 break; 941 } 942 #ifdef DEBUG 943 if (fLog) RTAssertMsg2("rebalance: %#2u: op #5, h=%d - \n", a_pStack->cEntries, cHeight); 944 #endif 816 945 pNode->cHeight = cHeight; 817 946 }
Note:
See TracChangeset
for help on using the changeset viewer.