00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef NL_HEAP_ALLOCATOR_INLINE_H
00027 #define NL_HEAP_ALLOCATOR_INLINE_H
00028
00029 #ifdef NL_HEAP_ALLOCATOR_INTERNAL_CHECKS
00030 #define internalAssert(a) memory_assert(a)
00031 #else // NL_HEAP_ALLOCATOR_INTERNAL_CHECKS
00032 #define internalAssert(a) ((void)0)
00033 #endif // NL_HEAP_ALLOCATOR_INTERNAL_CHECKS
00034
00035 #ifdef NL_HEAP_ALLOCATION_NDEBUG
00036
00037 #define NL_UPDATE_MAGIC_NUMBER(node) ((void)0)
00038 #define NL_UPDATE_MAGIC_NUMBER_FREE_NODE(node) ((void)0)
00039
00040 #else // NL_HEAP_ALLOCATION_NDEBUG
00041
00042 #define NL_UPDATE_MAGIC_NUMBER(node) {\
00043 uint32 crc = evalMagicNumber (node);\
00044 *(node->EndMagicNumber) = crc;\
00045 }
00046
00047 #define NL_UPDATE_MAGIC_NUMBER_FREE_NODE(node) {\
00048 if (node != &_NullNode.FreeNode) \
00049 { \
00050 uint32 crc = evalMagicNumber (getNode (node));\
00051 *(getNode (node)->EndMagicNumber) = crc;\
00052 } \
00053 }
00054
00055 #endif // NL_HEAP_ALLOCATION_NDEBUG
00056
00057 #if defined (NL_OS_WINDOWS)
00058 #define NL_ALLOC_STOP _asm { int 3 }
00059 #else
00060 #define NL_ALLOC_STOP abort()
00061 #endif
00062
00063
00064
00065
00066
00067 inline bool CHeapAllocator::isNodeFree (const CNodeBegin *node)
00068 {
00069 return (node->SizeAndFlags & CNodeBegin::Free) != 0;
00070 }
00071
00072
00073
00074 inline bool CHeapAllocator::isNodeUsed (const CNodeBegin *node)
00075 {
00076 return (node->SizeAndFlags & CNodeBegin::Free) == 0;
00077 }
00078
00079
00080
00081 inline bool CHeapAllocator::isNodeLast (const CNodeBegin *node)
00082 {
00083 return (node->SizeAndFlags & CNodeBegin::Last) != 0;
00084 }
00085
00086
00087
00088 inline bool CHeapAllocator::isNodeSmall (const CNodeBegin *node)
00089 {
00090 #ifdef NL_HEAP_NO_SMALL_BLOCK_OPTIMIZATION
00091 return false;
00092 #else // NL_HEAP_NO_SMALL_BLOCK_OPTIMIZATION
00093 return getNodeSize (node) <= LastSmallBlock;
00094 #endif // NL_HEAP_NO_SMALL_BLOCK_OPTIMIZATION
00095 }
00096
00097
00098
00099 inline bool CHeapAllocator::isNodeRed (const CFreeNode *node)
00100 {
00101 return (node->Flags & CFreeNode::Red) != 0;
00102 }
00103
00104
00105
00106 inline bool CHeapAllocator::isNodeBlack (const CFreeNode *node)
00107 {
00108 return (node->Flags & CFreeNode::Red) == 0;
00109 }
00110
00111
00112
00113 inline void CHeapAllocator::setNodeFree (CNodeBegin *node)
00114 {
00115 node->SizeAndFlags |= CNodeBegin::Free;
00116 }
00117
00118
00119
00120 inline void CHeapAllocator::setNodeUsed (CNodeBegin *node)
00121 {
00122 node->SizeAndFlags &= ~CNodeBegin::Free;
00123 }
00124
00125
00126
00127 inline void CHeapAllocator::setNodeLast (CNodeBegin *node, bool last)
00128 {
00129 if (last)
00130 node->SizeAndFlags |= CNodeBegin::Last;
00131 else
00132 node->SizeAndFlags &= ~CNodeBegin::Last;
00133 }
00134
00135
00136
00137 inline void CHeapAllocator::setNodeSize (CNodeBegin *node, uint size)
00138 {
00139
00140 internalAssert ((size&0xc0000000) == 0);
00141
00142
00143 node->SizeAndFlags &= ~CNodeBegin::SizeMask;
00144 node->SizeAndFlags |= size;
00145 }
00146
00147
00148
00149 inline void CHeapAllocator::setNodeColor (CFreeNode *node, bool red)
00150 {
00151 if (red)
00152 node->Flags |= CFreeNode::Red;
00153 else
00154 node->Flags &= ~CFreeNode::Red;
00155 }
00156
00157
00158
00159 inline void CHeapAllocator::setNodeRed (CFreeNode *node)
00160 {
00161 node->Flags |= CFreeNode::Red;
00162 }
00163
00164
00165
00166 inline void CHeapAllocator::setNodeBlack (CFreeNode *node)
00167 {
00168 node->Flags &= ~CFreeNode::Red;
00169 }
00170
00171
00172
00173
00174
00175 inline void CHeapAllocator::rotateLeft (CHeapAllocator::CFreeNode *x)
00176 {
00177
00178
00179
00180 CHeapAllocator::CFreeNode *y = x->Right;
00181 x->Right = y->Left;
00182 if (y->Left != &_NullNode.FreeNode)
00183 {
00184 y->Left->Parent = x;
00185 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (y->Left);
00186 }
00187
00188
00189 if (y != &_NullNode.FreeNode)
00190 y->Parent = x->Parent;
00191
00192
00193 if (x->Parent)
00194 {
00195
00196 if (x == x->Parent->Left)
00197 x->Parent->Left = y;
00198 else
00199 {
00200 internalAssert (x == x->Parent->Right);
00201 x->Parent->Right = y;
00202 }
00203 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (x->Parent);
00204 }
00205 else
00206 {
00207 internalAssert (x == _FreeTreeRoot);
00208 _FreeTreeRoot = y;
00209 }
00210
00211
00212 y->Left = x;
00213 if (x != &_NullNode.FreeNode)
00214 x->Parent = y;
00215 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (x);
00216 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (y);
00217 }
00218
00219
00220
00221 inline void CHeapAllocator::rotateRight (CHeapAllocator::CFreeNode *x)
00222 {
00223
00224
00225
00226 CHeapAllocator::CFreeNode *y = x->Left;
00227 x->Left = y->Right;
00228 if (y->Right != &_NullNode.FreeNode)
00229 {
00230 y->Right->Parent = x;
00231 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (y->Right);
00232 }
00233
00234
00235 if (y != &_NullNode.FreeNode)
00236 y->Parent = x->Parent;
00237
00238
00239 if (x->Parent)
00240 {
00241
00242 if (x == x->Parent->Right)
00243 {
00244 x->Parent->Right = y;
00245 }
00246 else
00247 {
00248 internalAssert (x == x->Parent->Left);
00249 x->Parent->Left = y;
00250 }
00251 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (x->Parent);
00252 }
00253 else
00254 {
00255 internalAssert (x == _FreeTreeRoot);
00256 _FreeTreeRoot = y;
00257 }
00258
00259
00260 y->Right = x;
00261 if (x != &_NullNode.FreeNode)
00262 x->Parent = y;
00263
00264
00265 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (x);
00266 NL_UPDATE_MAGIC_NUMBER_FREE_NODE (y);
00267 }
00268
00269
00270
00271 inline CHeapAllocator::CFreeNode *CHeapAllocator::find (uint size)
00272 {
00273 CHeapAllocator::CFreeNode *current = _FreeTreeRoot;
00274 CHeapAllocator::CFreeNode *smallest = NULL;
00275 while (current != &_NullNode.FreeNode)
00276 {
00277
00278 if (size <= getNodeSize (getNode (current)))
00279 {
00280
00281 smallest = current;
00282
00283
00284 current = current->Left;
00285 }
00286 else
00287 {
00288
00289 current = current->Right;
00290 }
00291 }
00292 return smallest;
00293 }
00294
00295
00296
00297
00298
00299 #ifndef NL_HEAP_ALLOCATION_NDEBUG
00300
00301 inline void CHeapAllocator::computeCRC32(uint32 &crc, const void* buffer, unsigned int count)
00302 {
00303 internalAssert ( (count&3) == 0);
00304 count >>= 2;
00305
00306 const uint32* ptr = (uint32*) buffer;
00307 while (count--)
00308 {
00309 crc ^= *(ptr++);
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 }
00332
00333 #endif // NL_HEAP_ALLOCATION_NDEBUG
00334
00335
00336
00337 inline const CHeapAllocator::CNodeBegin *CHeapAllocator::getFirstNode (const CMainBlock *mainBlock)
00338 {
00339
00340 return (CNodeBegin*)(((uint32)mainBlock->Ptr&~(Align-1)) + ((((uint32)mainBlock->Ptr&(Align-1))==0)? 0 : Align));
00341 }
00342
00343
00344
00345 inline CHeapAllocator::CNodeBegin *CHeapAllocator::getFirstNode (CMainBlock *mainBlock)
00346 {
00347
00348 return (CNodeBegin*)(((uint32)mainBlock->Ptr&~(Align-1)) + ((((uint32)mainBlock->Ptr&(Align-1))==0)? 0 : Align));
00349 }
00350
00351
00352
00353 inline const CHeapAllocator::CNodeBegin *CHeapAllocator::getNextNode (const CNodeBegin *current)
00354 {
00355
00356 if (isNodeLast (current))
00357 return NULL;
00358
00359
00360 return (const CNodeBegin*)((uint8*)current + sizeof (CNodeBegin) + NL_HEAP_NODE_END_SIZE + getNodeSize (current) );
00361 }
00362
00363
00364
00365 inline CHeapAllocator::CNodeBegin *CHeapAllocator::getNextNode (CNodeBegin *current)
00366 {
00367
00368 if (isNodeLast (current))
00369 return NULL;
00370
00371
00372 return (CNodeBegin*)((uint8*)current + sizeof (CNodeBegin) + NL_HEAP_NODE_END_SIZE + getNodeSize (current) );
00373 }
00374
00375
00376
00377 inline const CHeapAllocator::CFreeNode *CHeapAllocator::getFreeNode (const CNodeBegin *current)
00378 {
00379 return (const CHeapAllocator::CFreeNode *)((uint8*)current + sizeof(CNodeBegin));
00380 }
00381
00382
00383
00384 inline CHeapAllocator::CFreeNode *CHeapAllocator::getFreeNode (CNodeBegin *current)
00385 {
00386 return (CHeapAllocator::CFreeNode *)((uint8*)current + sizeof(CNodeBegin));
00387 }
00388
00389
00390
00391 inline const CHeapAllocator::CNodeBegin *CHeapAllocator::getNode (const CFreeNode *current)
00392 {
00393 return (const CHeapAllocator::CNodeBegin *)((uint8*)current - sizeof(CNodeBegin));
00394 }
00395
00396
00397
00398 inline CHeapAllocator::CNodeBegin *CHeapAllocator::getNode (CFreeNode *current)
00399 {
00400 return (CHeapAllocator::CNodeBegin *)((uint8*)current - sizeof(CNodeBegin));
00401 }
00402
00403
00404
00405 inline uint CHeapAllocator::getNodeSize (const CNodeBegin *current)
00406 {
00407 return current->SizeAndFlags & CNodeBegin::SizeMask;
00408 }
00409
00410
00411
00412 #ifndef NL_HEAP_ALLOCATION_NDEBUG
00413
00414 inline uint32 CHeapAllocator::evalMagicNumber (const CNodeBegin *node)
00415 {
00416 uint32 crc = (uint32)node;
00417
00418
00419 computeCRC32 (crc, node, sizeof(CNodeBegin));
00420
00421
00422 if ( isNodeFree (node) && !isNodeSmall (node) )
00423 computeCRC32 (crc, getFreeNode (node), sizeof(CFreeNode));
00424
00425
00426 return crc;
00427 }
00428
00429 #endif // NL_HEAP_ALLOCATION_NDEBUG
00430
00431
00432
00433
00434
00435 inline bool CHeapAllocator::checkNodeSB (const CSmallBlockPool *mainBlock, const CNodeBegin *previous, const CNodeBegin *current, const CNodeBegin *next, bool stopOnError) const
00436 {
00437 #ifndef NL_HEAP_ALLOCATION_NDEBUG
00438
00439 uint32 crc = evalMagicNumber (current);
00440
00441
00442 if (*(current->EndMagicNumber) != crc)
00443 {
00444
00445 if (stopOnError)
00446 {
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 NL_ALLOC_STOP;
00459 }
00460
00461
00462 return false;
00463 }
00464 #endif // NL_HEAP_ALLOCATION_NDEBUG
00465
00466
00467
00468
00469 if (
00470 ( (uint)current < ((uint)mainBlock) + sizeof (CSmallBlockPool)) ||
00471 ( (uint)current + getNodeSize (current) + sizeof(CNodeBegin) + NL_HEAP_NODE_END_SIZE >
00472 ((uint)mainBlock) + sizeof (CSmallBlockPool) + SmallBlockPoolSize * (sizeof(CNodeBegin)+ mainBlock->Size + NL_HEAP_NODE_END_SIZE) )
00473 )
00474 {
00475
00476 if (stopOnError)
00477 {
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 NL_ALLOC_STOP;
00489 }
00490
00491
00492 return false;
00493 }
00494
00495
00496 return true;
00497 }
00498
00499
00500
00501 inline bool CHeapAllocator::checkNodeLB (const CMainBlock *mainBlock, const CNodeBegin *previous, const CNodeBegin *current, const CNodeBegin *next, bool stopOnError) const
00502 {
00503 #ifndef NL_HEAP_ALLOCATION_NDEBUG
00504
00505 uint32 crc = evalMagicNumber (current);
00506
00507
00508 if (*(current->EndMagicNumber) != crc)
00509 {
00510
00511 if (stopOnError)
00512 {
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 NL_ALLOC_STOP;
00525 }
00526
00527
00528 return false;
00529 }
00530 #endif // NL_HEAP_ALLOCATION_NDEBUG
00531
00532
00533
00534
00535 if (
00536 ( (uint)current < (uint)mainBlock->Ptr ) ||
00537 ( (uint)current + getNodeSize (current) + sizeof(CNodeBegin) + NL_HEAP_NODE_END_SIZE >
00538 (uint)mainBlock->Ptr + mainBlock->Size )
00539 )
00540 {
00541
00542 if (stopOnError)
00543 {
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554 NL_ALLOC_STOP;
00555 }
00556
00557
00558 return false;
00559 }
00560
00561
00562 if ( !(current->Previous == NULL ||
00563 ( ((uint)current->Previous <= (uint)current - sizeof (CNodeBegin) - NL_HEAP_NODE_END_SIZE) &&
00564 ((uint)current->Previous >= (uint)mainBlock->Ptr) )
00565 ) )
00566 {
00567
00568 if (stopOnError)
00569 {
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 NL_ALLOC_STOP;
00581 }
00582
00583
00584 return false;
00585 }
00586
00587
00588 if (isNodeFree (current))
00589 {
00590
00591 const CFreeNode *freeNode = getFreeNode (current);
00592 checkFreeNode (freeNode, stopOnError, false);
00593 }
00594
00595
00596 return true;
00597 }
00598
00599
00600
00601 inline bool CHeapAllocator::checkFreeNode (const CFreeNode *current, bool stopOnError, bool recurse) const
00602 {
00603
00604 if (current != &_NullNode.FreeNode)
00605 {
00606
00607 const CNodeBegin *node = getNode (current);
00608
00609
00610 if ( !isNodeFree(node) )
00611 {
00612
00613 if (stopOnError)
00614 {
00615
00616
00617
00618
00619
00620 NL_ALLOC_STOP;
00621 }
00622
00623
00624 return false;
00625 }
00626
00627
00628 if (
00629 ( current->Left != &_NullNode.FreeNode && getNodeSize (getNode (current->Left)) > getNodeSize (node) ) ||
00630 ( current->Right != &_NullNode.FreeNode && getNodeSize (getNode (current->Right)) < getNodeSize (node) )
00631 )
00632 {
00633
00634 if (stopOnError)
00635 {
00636
00637
00638
00639
00640
00641 NL_ALLOC_STOP;
00642 }
00643
00644
00645 return false;
00646 }
00647
00648
00649 bool leftBlack = (current->Left == &_NullNode.FreeNode) || isNodeBlack(current->Left);
00650 bool rightBlack = (current->Right == &_NullNode.FreeNode) || isNodeBlack(current->Right);
00651 if ( !leftBlack && !rightBlack && isNodeRed (getFreeNode (node)) )
00652 {
00653
00654 if (stopOnError)
00655 {
00656
00657
00658
00659
00660
00661 NL_ALLOC_STOP;
00662 }
00663
00664
00665 return false;
00666 }
00667
00668
00669 if ( ( (current->Parent == NULL) && (_FreeTreeRoot != current) ) || ( (current->Parent != NULL) && (_FreeTreeRoot == current) ) )
00670 {
00671
00672 if (stopOnError)
00673 {
00674
00675
00676
00677
00678
00679 NL_ALLOC_STOP;
00680 }
00681
00682
00683 return false;
00684 }
00685
00686
00687 if (recurse)
00688 {
00689 if (!checkFreeNode (current->Left, stopOnError, recurse))
00690 return false;
00691 if (!checkFreeNode (current->Right, stopOnError, recurse))
00692 return false;
00693 }
00694 }
00695
00696
00697 return true;
00698 }
00699
00700
00701
00702
00703
00704 inline void CHeapAllocator::enterCriticalSectionSB () const
00705 {
00706 _MutexSB.enter ();
00707 }
00708
00709
00710
00711 inline void CHeapAllocator::leaveCriticalSectionSB () const
00712 {
00713 _MutexSB.leave ();
00714 }
00715
00716
00717
00718 inline void CHeapAllocator::enterCriticalSectionLB () const
00719 {
00720 _MutexLB.enter ();
00721 }
00722
00723
00724
00725 inline void CHeapAllocator::leaveCriticalSectionLB () const
00726 {
00727 _MutexLB.leave ();
00728 }
00729
00730
00731
00732 inline void CHeapAllocator::enterCriticalSection () const
00733 {
00734 enterCriticalSectionSB ();
00735 enterCriticalSectionLB ();
00736 }
00737
00738
00739
00740 inline void CHeapAllocator::leaveCriticalSection () const
00741 {
00742 leaveCriticalSectionLB ();
00743 leaveCriticalSectionSB ();
00744 }
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769 inline uint CHeapAllocator::getMainBlockCount () const
00770 {
00771 uint count = 0;
00772 CMainBlock *currentBlock = _MainBlockList;
00773 while (currentBlock)
00774 {
00775 currentBlock = currentBlock->Next;
00776 count++;
00777 }
00778 return count;
00779 }
00780
00781
00782
00783
00784
00785 #ifndef NL_HEAP_ALLOCATION_NDEBUG
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799 #endif // NL_HEAP_ALLOCATION_NDEBUG
00800
00801
00802
00803 inline void CHeapAllocator::setOutOfMemoryMode (TOutOfMemoryMode mode)
00804 {
00805 enterCriticalSection ();
00806
00807 _OutOfMemoryMode = mode;
00808
00809 leaveCriticalSection ();
00810 }
00811
00812
00813
00814 inline CHeapAllocator::TOutOfMemoryMode CHeapAllocator::getOutOfMemoryMode () const
00815 {
00816 return _OutOfMemoryMode;
00817 }
00818
00819
00820
00821 inline void CHeapAllocator::setBlockAllocationMode (TBlockAllocationMode mode)
00822 {
00823 enterCriticalSection ();
00824
00825 _BlockAllocationMode = mode;
00826
00827 leaveCriticalSection ();
00828 }
00829
00830
00831
00832 inline CHeapAllocator::TBlockAllocationMode CHeapAllocator::getBlockAllocationMode () const
00833 {
00834 return _BlockAllocationMode;
00835 }
00836
00837
00838
00839
00840 inline const char *CHeapAllocator::getName () const
00841 {
00842 return _Name;
00843 }
00844
00845
00846
00847 inline uint CHeapAllocator::getMainBlockSize () const
00848 {
00849 return _MainBlockSize;
00850 }
00851
00852
00853
00854
00855
00856
00857 inline CHeapAllocator::CNodeBegin *CHeapAllocator::getSmallBlock (CHeapAllocator::CSmallBlockPool *smallBlock, uint blockIndex)
00858 {
00859 return (CHeapAllocator::CNodeBegin*)((uint8*)smallBlock + sizeof (CSmallBlockPool) + blockIndex * (sizeof(CNodeBegin) + smallBlock->Size + NL_HEAP_NODE_END_SIZE) );
00860 }
00861
00862
00863
00864 inline CHeapAllocator::CNodeBegin *CHeapAllocator::getNextSmallBlock (CNodeBegin *previous)
00865 {
00866 return previous->Previous;
00867 }
00868
00869
00870
00871 inline void CHeapAllocator::setNextSmallBlock (CNodeBegin *previous, CNodeBegin *next)
00872 {
00873 previous->Previous = next;
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 #endif // NL_HEAP_ALLOCATOR_H