hkLargeBlockAllocator.h
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:27k
源码类别:

其他游戏

开发平台:

Visual C++

  1. /* 
  2.  * 
  3.  * Confidential Information of Telekinesys Research Limited (t/a Havok). Not for disclosure or distribution without Havok's
  4.  * prior written consent. This software contains code, techniques and know-how which is confidential and proprietary to Havok.
  5.  * Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2009 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
  6.  * 
  7.  */
  8. #ifndef HK_LARGE_BLOCK_ALLOCATOR_H
  9. #define HK_LARGE_BLOCK_ALLOCATOR_H
  10. // The hkLargeBlockAllocator implements the hkFreeListMemoryServer interface
  11. #include <Common/Base/Memory/Memory/FreeList/hkFreeListMemoryServer.h>
  12. struct hkMemoryStatistics;
  13.     /// Used for finding all of the used blocks
  14. typedef void (HK_CALL *hkMemBlockCallback)(void* start, hk_size_t blockSize,void* param);
  15. /// This class is an interface which the hkLargeBlockAllocator uses to get the underlying memory
  16. class hkMemoryBlockServer
  17. {
  18. public:
  19. HK_DECLARE_SYSTEM_ALLOCATOR();
  20. /// All allocs are guaranteed to fit this alignment
  21. enum { ALIGN = 16 };
  22. /// Dtor
  23. /// We'll have a virtual dtor so safe destruction through this interface
  24. virtual ~hkMemoryBlockServer() {}
  25. /// Returns true if this server is the single block style.
  26. /// There are two styles of servers supported. Ones which allocate a single block. The amount used can
  27. /// be varied potentially via the 'resize' mechanism. If it isn't the single block style then it is
  28. /// the multi-block style. Multi block allocators can allocate many blocks. Generally they do not support
  29. /// block resizing.
  30. virtual hkBool isSingleBlockServer() =0;
  31. /// Recommend a size that the server is best able to deal with.
  32. /// The server may deal want to deal with different sizes of allocations in different
  33. /// ways. This call for a given size will return a size either the same or greater that
  34. /// this server recommends for allocation. It is best to use what it returns because
  35. /// it will likely have less wastage too.
  36. virtual hk_size_t recommendSize(hk_size_t size) = 0;
  37. /// Allocates a chunk. All allocations are 16 byte aligned. Returns the actual size of the allocated block.
  38. virtual void* allocate(hk_size_t size, hk_size_t& sizeOut) =0;
  39. /// Frees a block allocated through alloc. The size must be the size returned from alloc.
  40. virtual void free(void* data, hk_size_t size) = 0;
  41. /// Given a block allocated with allocate will try and make it bigger or smaller. This can be thought of a generalization
  42. /// of sbrk. Returns true if the resize was successful - sizeOut is the new size of the block.
  43. virtual hkBool resize(void* data, hk_size_t oldSize, hk_size_t newSize, hk_size_t& sizeOut) = 0;
  44. /// Returns the recommended minimum allocation size. Doing allocations smaller that this could have
  45. /// messy consequences.
  46. hk_size_t getMinAllocSize() const { return m_minAllocSize; }
  47. /// Returns the total amount of unallocated memory available. If this isn't meaningful (for example
  48. /// with virtual memory its effectively infinate) the method will return hkMemoryStatistics::INFINTATE
  49. virtual hk_size_t getTotalAvailableMemory() = 0;
  50. /// Get the currently set memory limit. If 0, there is no memory limit
  51. virtual hk_size_t getMemoryLimit() = 0;
  52. /// Set the memory limit, will return true if successful
  53. /// Note the actual limit set may be slightly different than the value requested, to take into account alignment
  54. /// or other low level memory issues. Use getMemoryLimit to find out what the limit ended up being.
  55. virtual hkBool setMemoryLimit( hk_size_t ) =0;
  56. /// When memory becomes restricted, it may be necessary to allocate a small amount of space to
  57. /// clean up the 'mess'. A fast garbage collector often needs extra space to do its work for example.
  58. /// This functionality allows for allocations of 'short lived' and stack allocated style memory allocations,
  59. /// that can be used in this situation. Deallocations MUST be in the opposite order to allocations.
  60. virtual void* criticalAlloc(hk_size_t size) =0;
  61. /// To free a critical memory allocation
  62. virtual void criticalFree(void* ptr, hk_size_t size) =0;
  63. protected:
  64. hk_size_t m_minAllocSize;
  65. };
  66. class hkLargeBlockLimitedMemoryListener
  67. {
  68. public:
  69. HK_DECLARE_SYSTEM_ALLOCATOR();
  70. virtual ~hkLargeBlockLimitedMemoryListener(){}
  71. /// Called when a request is denied. An implementation can free up memory, and on
  72. /// returning from this call the allocator will try and allocate again.
  73. virtual void cannotAllocate(hk_size_t size) =0;
  74. /// This is called when the allocator has given up allocating. Generally this will be called after
  75. /// a call to cannotAllocate, although that is not a requirement of an implementation.
  76. virtual void allocationFailure(hk_size_t size) = 0;
  77. };
  78. /* This is a large memory block allocator, which is designed to handle allocations 256 bytes or larger. Smaller
  79. allocations will be serviced but will internally degenerate to a 256 byte block. Thus this allocator is not
  80. best used for small high performance chunks of memory. In that situation a freelist or pool memory style
  81. allocator is more suitable.
  82. What this allocator does allow for is good usage of varying sized chunks of memory. A 128k chunk of memory or a 2.7k
  83. chunk of memory both have the same same small overhead.
  84. The allocator is designed to be fast and efficient. When a block is requested a search is performed down a tree
  85. of available blocks to find the one most suitable. Most of the complexity of the algorithm comes from this inplace
  86. tree traversal.
  87. The allocator is designed to have good cache usage
  88. Some notes on the algorithm:
  89. o Adjacent free chunks are always merged - thus the chunks adjacent to a free chunk must be in use.
  90. o Each chunk consists of a header, which records the size of this block, and therefore implicitly the start of the next
  91. block.
  92. o Each header records
  93.   + If this chunk is in use
  94.   + If the previous chunk is in use
  95.   + If the previous chunk is NOT in use, how large the previous chunk is
  96. o When a chunk is not in use its header is 'extended' into the payload - such that the block can be a tree member
  97. o There is the concept of the 'top block' for allocations in a contiguous chunk of memory, this is where an
  98.   allocation would take place when all else fails
  99.   + In this algorithm the top block is special because its contents may not be correctly constructed
  100. o Allocations of actual memory go through the hkMemoryBlockServer
  101.   + Multiple non contiguous allocations are possible :)
  102.   + When this happens internally blocks are set up so the chunks of memory between the blocks owned by this allocator
  103.     appear as 'inuse', when in reality they don't belong to this allocator
  104. o Allocations from the hkMemoryBlockServer are held in hkMemPages
  105. */
  106. /*
  107. Possible future improvements:
  108. o Support for realloc style constructs
  109.   + For example returning if a block can be extended, and its current actual size, extending into a freeblock
  110. o Ideally there would be a realloc in there somewhere
  111. o Debugging support
  112.   + Having headers and footers
  113. */
  114. typedef unsigned int hkBinIndex;
  115. typedef unsigned int hkBinMap;
  116.     /// Has the same amount of bits as a hk_size_t but is signed.
  117. typedef int hkSignedSizeT;
  118. struct hkMemChunk
  119. {
  120. static const hk_size_t PINUSE_BIT = 1;
  121. static const hk_size_t CINUSE_BIT = 2;
  122. static const hk_size_t INUSE_BITS = 3;
  123.     static const hk_size_t ALIGN = 16;
  124. static const hk_size_t ALIGN_MASK = ALIGN-1;
  125. /// The bytes from the hkMemChunk to the payload inside
  126. /// Would be better to do sizeof(hkMemChunk), but I can't do that here - so I do sizeof(hk_size_t)*2
  127.     static const hk_size_t PAYLOAD_OFFSET = (sizeof(hk_size_t)*2 + ALIGN_MASK)&~ALIGN_MASK;
  128. /// Returns true if the previous block is in use
  129. HK_FORCE_INLINE bool isPinuse() const { return (head&PINUSE_BIT)!=0; }
  130. /// Returns true if this block is in use
  131. HK_FORCE_INLINE bool isInuse() const { return (head&CINUSE_BIT)!=0; }
  132.         /// The chunk size is the total size (including the hkMallocChunk data)
  133. HK_FORCE_INLINE hk_size_t getChunkSize() const { return (head&~INUSE_BITS); }
  134.         /// Clear the previous in use flag
  135. HK_FORCE_INLINE void clearPinuse() { head &= ~PINUSE_BIT; }
  136.         /// Clear the in use flag
  137. HK_FORCE_INLINE void clearInuse() { head &= ~CINUSE_BIT; }
  138. /// Returns the next chunks previous in use
  139. HK_FORCE_INLINE bool isNextPinuse() { return nextChunk()->isPinuse(); }
  140.         /// Get the address of the next chunk
  141. HK_FORCE_INLINE hkMemChunk* nextChunk() { return (hkMemChunk*)(((char*)this) + getChunkSize()); }
  142.         /// Get the address of the previous chunk
  143. HK_FORCE_INLINE hkMemChunk* previousChunk() { return (hkMemChunk*)(((char*)this) - prevFoot); }
  144.         /// Return memory as chunk x bytes after the chunk
  145. HK_FORCE_INLINE hkMemChunk* chunkPlusOffset(hk_size_t s) { return (hkMemChunk*)(((char*)this)+s); }
  146.         /// Return memory as chunk x bytes before the chunk
  147. HK_FORCE_INLINE hkMemChunk* chunkMinusOffset(hk_size_t s) { return (hkMemChunk*)(((char*)this)-s); }
  148.         /// Return the address of the contained data
  149.     HK_FORCE_INLINE void* getPayload() { return (void*)(((char*)this) + PAYLOAD_OFFSET); }
  150.         /// Get the size of the payload
  151.     HK_FORCE_INLINE hk_size_t getPayloadSize() { return getChunkSize() - PAYLOAD_OFFSET; }
  152.         /// Turn an address into a memory block
  153. HK_FORCE_INLINE static hkMemChunk* toChunk(void* in) { return (hkMemChunk*)(((char*)in) - PAYLOAD_OFFSET); }
  154.         /// Set cinuse and pinuse of this chunk and pinuse of next chunk
  155. HK_FORCE_INLINE void setInuseAndPinuse(hk_size_t s)
  156. {
  157. head = (s|PINUSE_BIT|CINUSE_BIT);
  158. hkMemChunk* next = chunkPlusOffset(s);
  159. next->head |= PINUSE_BIT;
  160. }
  161. /// Set inuse
  162.     HK_FORCE_INLINE void setInuse(hk_size_t s)
  163. {
  164. head = (head & PINUSE_BIT)|s|CINUSE_BIT;
  165. hkMemChunk* next = chunkPlusOffset(s);
  166. next->head |= PINUSE_BIT;
  167. }
  168. /// Set ths size, inuse and pinuse of the chunk
  169. HK_FORCE_INLINE void setSizeAndPinuseOfInuseChunk(hk_size_t s)
  170. {
  171. head = (s|PINUSE_BIT|CINUSE_BIT);
  172. }
  173. /// Get size at footer
  174. HK_FORCE_INLINE hk_size_t getFoot(hk_size_t s)  { return ((hkMemChunk*)(((char*)this)+s))->prevFoot; }
  175. /// Set the footer size
  176. HK_FORCE_INLINE void setFoot(hk_size_t s) { ((hkMemChunk*)(((char*)this) + s))->prevFoot = s; }
  177. /// Set size, pinuse bit, and foot
  178. HK_FORCE_INLINE void setSizeAndPinuseOfFreeChunk(hk_size_t s)
  179. {
  180. head = (s|PINUSE_BIT);
  181. setFoot(s);
  182. }
  183.         /// Set size, pinuse bit, foot, and clear next pinuse
  184. HK_FORCE_INLINE void setFreeWithPinuse(hk_size_t s,hkMemChunk* n)
  185. {
  186. n->clearPinuse();
  187. setSizeAndPinuseOfFreeChunk(s);
  188. }
  189.         /// Returns true if a pointer is aligned appropriately
  190.     static bool isAligned(void* ptr) { return (((hk_size_t)(ptr))&ALIGN_MASK)==0; }
  191. /// Members
  192.         /// Size of previous chunk including header etc (if free).
  193. hk_size_t prevFoot;
  194.         /// Size and inuse bits.
  195. hk_size_t head;
  196. };
  197. struct hkMemPage
  198. {
  199. /// The previous memory block
  200. hkMemPage* m_prev;
  201. /// The next memory block
  202. hkMemPage* m_next;
  203. /// Stores the amount of allocations in this page
  204. int m_numAllocs;
  205. /// The total size as passed back from the interface
  206. hk_size_t m_size;
  207. /// The payload start
  208. char* m_start;
  209. /// The payload end
  210. char* m_end;
  211. /// The first chunk in this page
  212. hkMemChunk* getFirstChunk() const { return (hkMemChunk*)m_start; }
  213. /// The last chunk in this page
  214. hkMemChunk* getFooter() const { return (hkMemChunk*)(m_end - hkMemChunk::PAYLOAD_OFFSET); }
  215. /// If there is nothing in the page this is the size of a chunk from the start of available space
  216. /// up to the footer. Its the largest free block that can be stored in a page.
  217. hk_size_t getMaxChunkSize() const { return  (m_end - m_start) - hkMemChunk::PAYLOAD_OFFSET; }
  218. // The contents size
  219. hk_size_t getContentsSize() const { return hk_size_t(m_end - m_start); }
  220. /// Gets the start of the contents
  221. char* getStart() const { return m_start;  }
  222. /// Gets a byte past the end
  223. char* getEnd() { return m_end; }
  224. };
  225. /// Assumes the fields are placed after hkMemChunk
  226. struct hkFreeMemChunk:public hkMemChunk
  227. {
  228. ///  double links -- used only if free.
  229. hkFreeMemChunk* next;
  230. hkFreeMemChunk* prev;
  231. };
  232. /*
  233. Description of the underlying structure
  234. ----------------------------------------
  235. Based on large block strategy of the Doug Lea allocator.
  236. Larger chunks are kept in a form of bitwise digital trees (aka
  237. tries) keyed on chunksizes.  Because 'tree chunks' are only for
  238. free chunks greater than 256 bytes, their size doesn't impose any
  239. constraints on user chunk sizes.  Each node looks like:
  240. chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  241. |             Size of previous chunk                            |
  242. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  243. `head:' |             Size of chunk, in bytes                         |P|
  244. mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  245. |             Forward pointer to next chunk of same size        |
  246. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  247. |             Back pointer to previous chunk of same size       |
  248. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  249. |             Pointer to left child (child[0])                  |
  250. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  251. |             Pointer to right child (child[1])                 |
  252. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  253. |             Pointer to parent                                 |
  254. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  255. |             bin index of this chunk                           |
  256. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  257. |             Unused space                                      .
  258. .                                                               |
  259. nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  260. `foot:' |             Size of chunk, in bytes                           |
  261. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  262. Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
  263. of the same size are arranged in a circularly-linked list, with only
  264. the oldest chunk (the next to be used, in our FIFO ordering)
  265. actually in the tree.  (Tree members are distinguished by a non-null
  266. parent pointer.)  If a chunk with the same size an an existing node
  267. is inserted, it is linked off the existing node using pointers that
  268. work in the same way as fd/bk pointers of small chunks.
  269. Each tree contains a power of 2 sized range of chunk sizes (the
  270. smallest is 0x100 <= x < 0x180), which is is divided in half at each
  271. tree level, with the chunks in the smaller half of the range (0x100
  272. <= x < 0x140 for the top nose) in the left subtree and the larger
  273. half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
  274. done by inspecting individual bits.
  275. Using these rules, each node's left subtree contains all smaller
  276. sizes than its right subtree.  However, the node at the root of each
  277. subtree has no particular ordering relationship to either.  (The
  278. dividing line between the subtree sizes is based on trie relation.)
  279. If we remove the last chunk of a given size from the interior of the
  280. tree, we need to replace it with a leaf node.  The tree ordering
  281. rules permit a node to be replaced by any leaf below it.
  282. The smallest chunk in a tree (a common operation in a best-fit
  283. allocator) can be found by walking a path to the leftmost leaf in
  284. the tree.  Unlike a usual binary tree, where we follow left child
  285. pointers until we reach a null, here we follow the right child
  286. pointer any time the left one is null, until we reach a leaf with
  287. both child pointers null. The smallest chunk in the tree will be
  288. somewhere along that path.
  289. The worst case number of steps to add, find, or remove a node is
  290. bounded by the number of bits differentiating chunks within
  291. bins. Under current bin calculations, this ranges from 6 up to 21
  292. (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
  293. is of course much better.
  294. */
  295. struct hkMemTreeChunk:public hkFreeMemChunk
  296. {
  297. hkMemTreeChunk* child[2];
  298. hkMemTreeChunk* parent;
  299. hkBinIndex index;
  300. /// The leftmost child
  301. hkMemTreeChunk* leftMostChild() const { return child[0]?child[0]:child[1]; }
  302. };
  303. class hkLargeBlockAllocator:public hkFreeListMemoryServer
  304. {
  305.     public:
  306. enum AllocType { CRITICAL_ALLOC,NORMAL_ALLOC };
  307. HK_DECLARE_SYSTEM_ALLOCATOR();
  308.             /// Ctor
  309.         hkLargeBlockAllocator(hkMemoryBlockServer* server);
  310.             /// Dtor
  311.         ~hkLargeBlockAllocator();
  312.         /// implementing hkFreeListMemoryServer
  313.         virtual void* alloc(hk_size_t size);
  314.         virtual void free(void* data);
  315.         virtual hkBool isValidAlloc(void* alloc);
  316.         virtual hk_size_t getAllocSize(void* p,hk_size_t size);
  317.         virtual hk_size_t getAllocTotalSize(void* p,hk_size_t size);
  318.         virtual void* criticalAlloc(hk_size_t size);
  319.         virtual void criticalFree(void* ptr,hk_size_t size);
  320.             /// Frees all allocations
  321.         void freeAll();
  322.             /// Called for all of the allocated chunks of memory
  323.         void forAllAllocs(hkMemBlockCallback callback,void* param);
  324.             /// Get the estimated size of an allocation
  325.         hk_size_t getEstimatedAllocSize(hk_size_t size) const;
  326.             /// Resizes a block - is guarenteed to succeed if the size is less than or equal to the size returned by getSize.
  327.             /// Does not allow to make a block bigger than what was returned from getAllocSize
  328.             /// disabled - has a nasty bug
  329.         ///void resizeAlloc(void* p,hk_size_t newSize);
  330.             /// Determines if mem points to a valid block
  331.         //hkBool checkAlloc(void* mem);
  332.         /// Runs thru all the allocations making sure they appear valid. Will return false if any seems invalid
  333.         hkBool checkAllocations(void** allocs,int size);
  334.             /// Get the statistics
  335.         void calculateStatistics(hkMemoryStatistics& stats);
  336.             /// Free up any unused space
  337.         void garbageCollect();
  338.             /// Set the limited memory listener
  339.         void setLimitedMemoryListener(hkLargeBlockLimitedMemoryListener* listener) { m_limitedListener = listener; }
  340.             /// Get the limited memory listener
  341.         hkLargeBlockLimitedMemoryListener* getLimitedMemoryListener() const { return m_limitedListener; }
  342.             /// Works out what the largest block available is
  343.         hk_size_t findLargestBlockSize();
  344.             /// Get the top block size
  345.         hk_size_t getTopBlockSize() const { return m_topsize; }
  346.             /// Returns the total amount of memory used in bytes
  347.         hk_size_t getTotalMemoryUsed() const { return m_used; }
  348.             /// Returns the total amount of memory allocated in bytes
  349.         hk_size_t calculateTotalMemoryAllocated() const;
  350.         class Iterator
  351.         {
  352.             public:
  353.             Iterator(hkMemChunk* chunk,hkMemPage* page,hkMemChunk* end):
  354.                 m_chunk(chunk),
  355.                 m_page(page),
  356.                 m_end(end)
  357.             {}
  358.             Iterator():
  359.                 m_chunk(HK_NULL)    /// Make invalid
  360.             {}
  361.             hkBool isValid() const { return m_chunk != HK_NULL; }
  362.             hk_size_t getSize() const { return m_chunk->getChunkSize(); }
  363.             void* getAddress() const { return m_chunk->getPayload(); }
  364.             hkBool isInuse() const { return m_chunk->isInuse(); }
  365.             hkMemChunk* m_chunk;
  366.             hkMemPage* m_page;
  367.             hkMemChunk* m_end;
  368.         };
  369.             /// Gets an iterator
  370.             /// Doing any allocations/frees will cause undefined behaviour
  371.             /// Blocks will be returned in order from lowest to highest in memory
  372.         Iterator getIterator();
  373.             /// Moves the iterator to the next block of memory. Returns false if the iterator is now invalid
  374.         hkBool nextBlock(Iterator& iter);
  375.             /// Get the block server
  376.         hkMemoryBlockServer* getBlockServer() const { return m_server; }
  377.             /// Ctor
  378.         hkLargeBlockAllocator();
  379. #ifdef HK_DEBUG
  380.         static void HK_CALL selfTest();
  381.         static void HK_CALL allocatorTest(hkLargeBlockAllocator& allocator,int testSize);
  382. #endif
  383. protected:
  384.                 /// Number of tree bins
  385.         static const unsigned int NTREEBINS =  (32U);
  386.                 /// The shift used to get tree bins
  387.         static const unsigned int TREEBIN_SHIFT = (8U);
  388.                 /// The miniumum large block size
  389.         static const hk_size_t MIN_LARGE_SIZE = hk_size_t(1)<< TREEBIN_SHIFT;
  390.         /// Amount of bits in a size_t
  391.         static const hk_size_t SIZE_T_BITSIZE = (sizeof(hk_size_t) << 3);
  392.             /// Returns true if an an allocated block looks correctly formed
  393.         hkBool _checkUsedAlloc(void* mem);
  394.             /// If called after a successful free should return true
  395.         hkBool _checkFreeChunk( hkMemChunk* p);
  396.             /// The amount of memory used is cached - and returned by getTotalMemoryUsed. This method works out by traversing
  397.             /// all the blocks how much memory is used
  398.         hk_size_t _calculateUsed() const;
  399.         hk_size_t _findLargestTreeBlockSize(hkMemTreeChunk* t,hk_size_t largest);
  400.         void _markTreeMap(hkBinIndex i) { m_treemap |= (1<<i); }
  401.         void _clearTreeMap(hkBinIndex i) { m_treemap &= ~(1<<i); }
  402.         bool _isTreeMapMarked(hkBinIndex i) const { return (m_treemap&(1<<i))!=0; }
  403.         void _insertLargeChunk( hkMemTreeChunk* x, hk_size_t s);
  404.         void _unlinkLargeChunk( hkMemTreeChunk* x);
  405.         void* _allocLarge( hk_size_t nb);
  406.         void* _allocFromTop(hk_size_t bytes);
  407.         void _makeTopValid() const;
  408.         void* _alloc(hk_size_t nb);
  409.         void _init();
  410.             // How the hades does this work?
  411.         static hkBinIndex _computeTreeIndex(hk_size_t s)
  412.         {
  413.             hk_size_t x = s >> TREEBIN_SHIFT;
  414.                 if (x == 0) { return 0; }
  415.                 if (x > 0xFFFF) { return NTREEBINS-1; }
  416.             unsigned int y = (unsigned int)x;
  417.             unsigned int n = ((y - 0x100) >> 16) & 8;
  418.             unsigned int k = (((y <<= n) - 0x1000) >> 16) & 4;
  419.             n += k;
  420.             n += k = (((y <<= k) - 0x4000) >> 16) & 2;
  421.             k = 14 - n + ((y <<= k) >> 15);
  422.             return (hkBinIndex)((k << 1) + ((s >> (k + (TREEBIN_SHIFT-1)) & 1)));
  423.         }
  424.         static hkBinIndex _bitToIndex(unsigned int x)
  425.         {
  426.             unsigned int y = x - 1;
  427.             unsigned int k = y >> (16-4) & 16;
  428.             unsigned int n = k;        y >>= k;
  429.             n += k = y >> (8-3) &  8;  y >>= k;
  430.             n += k = y >> (4-2) &  4;  y >>= k;
  431.             n += k = y >> (2-1) &  2;  y >>= k;
  432.             n += k = y >> (1-0) &  1;  y >>= k;
  433.             return n+y;
  434.         }
  435.         /// pad request bytes into a usable size
  436.         HK_FORCE_INLINE static hk_size_t _padRequest(hk_size_t req)
  437.         {
  438.             return (req + hkMemChunk::PAYLOAD_OFFSET + hkMemChunk::ALIGN_MASK)&~hkMemChunk::ALIGN_MASK;
  439.         }
  440.                 /// Bit representing maximum resolved size in a treebin at i
  441.         static int _bitForTreeIndex(int i)
  442.         {
  443.             return (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2);
  444.         }
  445.                 /// Shift placing maximum resolved bit in a treebin at i as sign bit
  446.         static int _leftShiftForTreeIndex(int i)
  447.         {
  448.             return ((i == NTREEBINS-1)? 0 : ((SIZE_T_BITSIZE-hk_size_t(1)) - ((i >> 1) + TREEBIN_SHIFT - 2)));
  449.         }
  450.                 /// The size of the smallest chunk held in bin with index i
  451.         static hk_size_t _minSizeForTreeIndex(int i)
  452.         {
  453.             return ((hk_size_t(1) << (((i) >> 1) + TREEBIN_SHIFT)) |  (((hk_size_t)((i) & hk_size_t(1))) << (((i) >> 1) + TREEBIN_SHIFT - 1)));
  454.         }
  455.             /// Trys to resize the page allocated from a SingleBlockServer. If successful will fix up the top block etc
  456.         hkBool _resizeSingleBlockServerPage(hk_size_t newSize);
  457.             /// Returns true if n is greater than p
  458.         template <typename S,typename T>
  459.         static bool _okNext(const S* p,const T* n) { return ((const char*)(p) < (const char*)(n)); }
  460.             /// Does noddy checks to see if an address is possibly correct
  461.         HK_FORCE_INLINE bool _isOkAddress(void *a) { return ((char*)(a) >= m_leastAddr); }
  462.             /// isolate the least set bit of a bitmap
  463.         HK_FORCE_INLINE static int _leastBit(int x) { return ((x) & -(x)); }
  464.             /// mask with all bits to left of least bit of x on
  465.         HK_FORCE_INLINE static int _leftBits(int x) { return ((x<<1) | -(x<<1)); }
  466.             /// An index to a set bit
  467.         HK_FORCE_INLINE static int _indexToBit(int x) { return 1<<x; }
  468.             /// mask with all bits to left of or equal to least bit of x on
  469.         HK_FORCE_INLINE static int _sameOrLeftBits(int x) { return ((x) | -(x)); }
  470.         static HK_FORCE_INLINE hkBool _comparePointers( void* a,void* b)
  471.         {
  472.             return (char*)a < (char*)b;
  473.         }
  474.             /// True if there are no allocated pages
  475.         hkBool _hasPages() { return m_pages.m_next != &m_pages; }
  476.         static void HK_CALL _addAlloc(void* data,hk_size_t size,void* param);
  477. protected:
  478.     // A listener which handles situations when memory allocation gets tight
  479.         hkLargeBlockLimitedMemoryListener* m_limitedListener;
  480. // A bit field with a bit indicating if a tree bucket has contents or not
  481.         hkBinMap m_treemap;
  482. //
  483.         char* m_leastAddr;
  484. // The 'topmost memory' chunk
  485.         hkMemChunk* m_top;
  486. // Cached size of topmost block
  487.         hk_size_t m_topsize;
  488. // The tree bins
  489.         hkMemTreeChunk* m_treebins[NTREEBINS];
  490. // Server for getting large memory blocks
  491.         hkMemoryBlockServer* m_server;
  492. // Used as top when starting up
  493. hkMemChunk m_zeroChunk;
  494. // This dummy page is the start of a doubly linked list of memory pages allocated through the server interface
  495. hkMemPage m_pages;
  496. // The total amount of used (allocated) memory
  497. hk_size_t m_used;
  498. };
  499. #endif // HK_LARGE_BLOCK_ALLOCATOR_H
  500. /*
  501. * Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20090216)
  502. * Confidential Information of Havok.  (C) Copyright 1999-2009
  503. * Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
  504. * Logo, and the Havok buzzsaw logo are trademarks of Havok.  Title, ownership
  505. * rights, and intellectual property rights in the Havok software remain in
  506. * Havok and/or its suppliers.
  507. * Use of this software for evaluation purposes is subject to and indicates
  508. * acceptance of the End User licence Agreement for this product. A copy of
  509. * the license is included with this software and is also available at www.havok.com/tryhavok.
  510. */