nlalloc_test.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Copyright 2010-2019 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  4. */
  5. #include "test.h"
  6. #include <bx/sort.h>
  7. #include <bx/allocator.h>
  8. bx::DefaultAllocator g_allocator0;
  9. struct TinyStlAllocator
  10. {
  11. static void* static_allocate(size_t _bytes)
  12. {
  13. return BX_ALLOC(&g_allocator0, _bytes);
  14. }
  15. static void static_deallocate(void* _ptr, size_t /*_bytes*/)
  16. {
  17. if (NULL != _ptr)
  18. {
  19. BX_FREE(&g_allocator0, _ptr);
  20. }
  21. }
  22. };
  23. #define TINYSTL_ALLOCATOR ::TinyStlAllocator
  24. #include <tinystl/vector.h>
  25. namespace stl = tinystl;
  26. namespace bx
  27. {
  28. struct Blk
  29. {
  30. static constexpr uint64_t kInvalid = UINT64_MAX;
  31. Blk()
  32. : ptr(kInvalid)
  33. , size(0)
  34. {
  35. }
  36. Blk(uint64_t _ptr, uint32_t _size)
  37. : ptr(_ptr)
  38. , size(_size)
  39. {
  40. }
  41. uint64_t ptr;
  42. uint32_t size;
  43. };
  44. inline bool operator<(const Blk& _lhs, const Blk& _rhs)
  45. {
  46. return _lhs.ptr < _rhs.ptr;
  47. }
  48. inline bool isValid(const Blk& _blk)
  49. {
  50. return Blk::kInvalid != _blk.ptr;
  51. }
  52. // First-fit non-local allocator.
  53. class NonLocalAllocator
  54. {
  55. public:
  56. static constexpr uint32_t kMinBlockSize = 16u;
  57. NonLocalAllocator()
  58. {
  59. reset();
  60. }
  61. ~NonLocalAllocator()
  62. {
  63. }
  64. void reset()
  65. {
  66. m_free.clear();
  67. m_used = 0;
  68. }
  69. void add(const Blk& _blk)
  70. {
  71. m_free.push_back(_blk);
  72. }
  73. Blk remove()
  74. {
  75. BX_CHECK(0 == m_used, "");
  76. if (0 < m_free.size() )
  77. {
  78. Blk freeBlock = m_free.back();
  79. m_free.pop_back();
  80. return freeBlock;
  81. }
  82. return Blk{};
  83. }
  84. Blk alloc(uint32_t _size)
  85. {
  86. _size = max(_size, kMinBlockSize);
  87. for (FreeList::iterator it = m_free.begin(), itEnd = m_free.end(); it != itEnd; ++it)
  88. {
  89. if (it->size >= _size)
  90. {
  91. const uint64_t ptr = it->ptr;
  92. if (it->size != _size)
  93. {
  94. it->size -= _size;
  95. it->ptr += _size;
  96. }
  97. else
  98. {
  99. m_free.erase(it);
  100. }
  101. m_used += _size;
  102. return Blk{ ptr, _size };
  103. }
  104. }
  105. // there is no block large enough.
  106. return Blk{};
  107. }
  108. void free(const Blk& _blk)
  109. {
  110. BX_CHECK(isValid(_blk), "Freeing invalid block!");
  111. m_used -= _blk.size;
  112. FreeList::iterator it = m_free.begin();
  113. FreeList::iterator itEnd = m_free.end();
  114. for (; it != itEnd; ++it)
  115. {
  116. if ( (_blk.ptr + _blk.size) == it->ptr)
  117. {
  118. it->ptr = _blk.ptr;
  119. it->size += _blk.size;
  120. break;
  121. }
  122. if (_blk.ptr > it->ptr)
  123. {
  124. m_free.insert(it, _blk);
  125. break;
  126. }
  127. }
  128. if (it == itEnd)
  129. {
  130. m_free.push_back(_blk);
  131. }
  132. }
  133. uint32_t getUsed() const
  134. {
  135. return m_used;
  136. }
  137. private:
  138. typedef stl::vector<Blk> FreeList;
  139. FreeList m_free;
  140. uint32_t m_used;
  141. };
  142. constexpr uint32_t NonLocalAllocator::kMinBlockSize;
  143. } // namespace bx
  144. TEST_CASE("nlalloc")
  145. {
  146. bx::NonLocalAllocator nla;
  147. bx::Blk blk;
  148. blk = nla.alloc(100);
  149. REQUIRE(!isValid(blk) );
  150. nla.add(bx::Blk{0x1000, 1024});
  151. blk = nla.alloc(1024);
  152. REQUIRE(isValid(blk) );
  153. bx::Blk blk2 = nla.alloc(1);
  154. REQUIRE(!isValid(blk2) );
  155. nla.free(blk);
  156. REQUIRE(0 == nla.getUsed() );
  157. {
  158. bx::Blk blk3 = nla.alloc(123);
  159. REQUIRE(isValid(blk3) );
  160. bx::Blk blk4 = nla.alloc(134);
  161. REQUIRE(isValid(blk4) );
  162. bx::Blk blk5 = nla.alloc(145);
  163. REQUIRE(isValid(blk5) );
  164. bx::Blk blk6 = nla.alloc(156);
  165. REQUIRE(isValid(blk6) );
  166. bx::Blk blk7 = nla.alloc(167);
  167. REQUIRE(isValid(blk7) );
  168. nla.free(blk3);
  169. nla.free(blk5);
  170. nla.free(blk7);
  171. nla.free(blk4);
  172. nla.free(blk6);
  173. REQUIRE(0 == nla.getUsed() );
  174. }
  175. blk2 = nla.alloc(1);
  176. REQUIRE(isValid(blk2) );
  177. REQUIRE(bx::NonLocalAllocator::kMinBlockSize == nla.getUsed() );
  178. nla.free(blk2);
  179. REQUIRE(0 == nla.getUsed() );
  180. }