nlalloc_test.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. m_used -= _blk.size;
  111. m_free.push_back(_blk);
  112. compact();
  113. }
  114. bool compact()
  115. {
  116. bx::quickSort(
  117. m_free.begin()
  118. , uint32_t(m_free.end() - m_free.begin() )
  119. , sizeof(Blk)
  120. , [](const void* _a, const void* _b) -> int32_t
  121. {
  122. const Blk& lhs = *(const Blk*)(_a);
  123. const Blk& rhs = *(const Blk*)(_b);
  124. return lhs < rhs ? -1 : 1;
  125. });
  126. for (FreeList::iterator it = m_free.begin(), next = it, itEnd = m_free.end(); next != itEnd;)
  127. {
  128. if ( (it->ptr + it->size) == next->ptr)
  129. {
  130. it->size += next->size;
  131. next = m_free.erase(next);
  132. }
  133. else
  134. {
  135. it = next;
  136. ++next;
  137. }
  138. }
  139. return 0 == m_used;
  140. }
  141. uint32_t getUsed() const
  142. {
  143. return m_used;
  144. }
  145. private:
  146. typedef stl::vector<Blk> FreeList;
  147. FreeList m_free;
  148. uint32_t m_used;
  149. };
  150. constexpr uint32_t NonLocalAllocator::kMinBlockSize;
  151. } // namespace bx
  152. TEST_CASE("nlalloc")
  153. {
  154. bx::NonLocalAllocator nla;
  155. bx::Blk blk;
  156. blk = nla.alloc(100);
  157. REQUIRE(!isValid(blk) );
  158. nla.add(bx::Blk{0x1000, 100});
  159. blk = nla.alloc(100);
  160. REQUIRE(isValid(blk) );
  161. bx::Blk blk2 = nla.alloc(1);
  162. REQUIRE(!isValid(blk2) );
  163. nla.free(blk);
  164. REQUIRE(0 == nla.getUsed() );
  165. blk2 = nla.alloc(1);
  166. REQUIRE(isValid(blk2) );
  167. REQUIRE(bx::NonLocalAllocator::kMinBlockSize == nla.getUsed() );
  168. nla.free(blk2);
  169. REQUIRE(0 == nla.getUsed() );
  170. }