allocator.hpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #pragma once
  2. #include <new>
  3. #include <utility>
  4. #include <type_traits>
  5. #include <bit>
  6. #include <stdint.h>
  7. #include <types/cplusplus.hpp>
  8. #include <types/types.h>
  9. namespace types {
  10. namespace __allocator {
  11. class brk_memory_allocator {
  12. public:
  13. using byte = uint8_t;
  14. using size_type = size_t;
  15. struct mem_blk_flags {
  16. uint8_t is_free;
  17. uint8_t has_next;
  18. uint8_t _unused2;
  19. uint8_t _unused3;
  20. };
  21. struct mem_blk {
  22. size_t size;
  23. struct mem_blk_flags flags;
  24. // the first byte of the memory space
  25. // the minimal allocated space is 8 bytes
  26. byte data[];
  27. };
  28. private:
  29. byte* p_start;
  30. byte* p_break;
  31. byte* p_limit;
  32. brk_memory_allocator() = delete;
  33. brk_memory_allocator(const brk_memory_allocator&) = delete;
  34. brk_memory_allocator(brk_memory_allocator&&) = delete;
  35. constexpr byte* brk(byte* addr)
  36. {
  37. if (unlikely(addr >= p_limit))
  38. return nullptr;
  39. return p_break = addr;
  40. }
  41. constexpr byte* sbrk(size_type increment)
  42. { return brk(p_break + increment); }
  43. constexpr mem_blk* _next(mem_blk* blk, size_type blk_size)
  44. {
  45. auto* p = std::bit_cast<byte*>(blk);
  46. p += sizeof(mem_blk);
  47. p += blk_size;
  48. return std::bit_cast<mem_blk*>(p);
  49. }
  50. // blk MUST be free
  51. constexpr void unite_afterwards(mem_blk* blk)
  52. {
  53. while (blk->flags.has_next) {
  54. auto* blk_next = _next(blk, blk->size);
  55. if (!blk_next->flags.is_free)
  56. break;
  57. blk->size += sizeof(mem_blk) + blk_next->size;
  58. blk->flags.has_next = blk_next->flags.has_next;
  59. }
  60. }
  61. // @param start_pos position where to start finding
  62. // @param size the size of the block we're looking for
  63. // @return found block if suitable block exists, if not, the last block
  64. constexpr mem_blk* find_blk(mem_blk* start_pos, size_type size)
  65. {
  66. while (true) {
  67. if (start_pos->flags.is_free) {
  68. unite_afterwards(start_pos);
  69. if (start_pos->size >= size)
  70. break;
  71. }
  72. if (!start_pos->flags.has_next)
  73. break;
  74. start_pos = _next(start_pos, start_pos->size);
  75. }
  76. return start_pos;
  77. }
  78. constexpr mem_blk* allocate_new_block(mem_blk* blk_before, size_type size)
  79. {
  80. auto ret = sbrk(sizeof(mem_blk) + size);
  81. if (!ret)
  82. return nullptr;
  83. mem_blk* blk = _next(blk_before, blk_before->size);
  84. blk_before->flags.has_next = 1;
  85. blk->flags.has_next = 0;
  86. blk->flags.is_free = 1;
  87. blk->size = size;
  88. return blk;
  89. }
  90. constexpr void split_block(mem_blk* blk, size_type this_size)
  91. {
  92. // block is too small to get split
  93. // that is, the block to be split should have enough room
  94. // for "this_size" bytes and also could contain a new block
  95. if (blk->size < this_size + sizeof(mem_blk) + 8)
  96. return;
  97. mem_blk* blk_next = _next(blk, this_size);
  98. blk_next->size = blk->size
  99. - this_size
  100. - sizeof(mem_blk);
  101. blk_next->flags.has_next = blk->flags.has_next;
  102. blk_next->flags.is_free = 1;
  103. blk->flags.has_next = 1;
  104. blk->size = this_size;
  105. }
  106. public:
  107. constexpr brk_memory_allocator(byte* start, size_type limit)
  108. : p_start(start)
  109. , p_limit(start + limit)
  110. {
  111. brk(p_start);
  112. auto* p_blk = std::bit_cast<mem_blk*>(sbrk(0));
  113. p_blk->size = 8;
  114. p_blk->flags.has_next = 0;
  115. p_blk->flags.is_free = 1;
  116. }
  117. constexpr void* alloc(size_type size)
  118. {
  119. // align to 8 bytes boundary
  120. size = (size + 7) & ~7;
  121. auto* block_allocated = find_blk(std::bit_cast<mem_blk*>(p_start), size);
  122. if (!block_allocated->flags.has_next
  123. && (!block_allocated->flags.is_free || block_allocated->size < size)) {
  124. // 'block_allocated' in the argument list is the pointer
  125. // pointing to the last block
  126. block_allocated = allocate_new_block(block_allocated, size);
  127. if (!block_allocated)
  128. return nullptr;
  129. } else {
  130. split_block(block_allocated, size);
  131. }
  132. block_allocated->flags.is_free = 0;
  133. auto* blkpos = std::bit_cast<byte*>(block_allocated);
  134. if (blkpos > p_start)
  135. p_start = blkpos;
  136. return block_allocated->data;
  137. }
  138. constexpr void free(void* ptr)
  139. {
  140. auto* blk = std::bit_cast<mem_blk*>(
  141. std::bit_cast<byte*>(ptr) - sizeof(mem_blk));
  142. blk->flags.is_free = 1;
  143. if (std::bit_cast<byte*>(blk) < p_start)
  144. p_start = std::bit_cast<byte*>(blk);
  145. // unite free blocks nearby
  146. unite_afterwards(blk);
  147. }
  148. };
  149. }; // namespace __allocator
  150. template <typename T>
  151. concept Allocator = requires(size_t size, typename T::value_type* ptr)
  152. {
  153. typename T::value_type;
  154. {
  155. T::allocate_memory(size)
  156. };
  157. {
  158. T::deallocate_memory(ptr)
  159. };
  160. std::is_same_v<typename T::value_type*, decltype(T::allocate_memory(size))>;
  161. std::is_same_v<void, decltype(T::deallocate_memory(ptr))>;
  162. };
  163. template <Allocator T>
  164. class allocator_traits;
  165. namespace __allocator {
  166. inline char __ident_heap[0x100000];
  167. inline __allocator::brk_memory_allocator
  168. m_alloc { (uint8_t*)__ident_heap, sizeof(__ident_heap) };
  169. } // namespace __allocator
  170. template <typename T>
  171. class kernel_ident_allocator {
  172. public:
  173. using value_type = T;
  174. static constexpr value_type* allocate_memory(size_t count)
  175. {
  176. return static_cast<value_type*>(__allocator::m_alloc.alloc(count));
  177. }
  178. static constexpr void deallocate_memory(value_type* ptr)
  179. {
  180. __allocator::m_alloc.free(ptr);
  181. }
  182. };
  183. template <template <typename _T> class Allocator, typename T, typename... Args>
  184. constexpr T* _new(Args&&... args)
  185. {
  186. return allocator_traits<Allocator<T>>::allocate_and_construct(std::forward<Args>(args)...);
  187. }
  188. template <template <typename _T> class Allocator, typename T, typename... Args>
  189. constexpr T* pnew(T* = nullptr, Args&&... args)
  190. {
  191. return _new<Allocator, T, Args...>(std::forward<Args>(args)...);
  192. }
  193. template <template <typename _T> class Allocator, typename T>
  194. constexpr void pdelete(T* ptr)
  195. {
  196. allocator_traits<Allocator<T>>::deconstruct_and_deallocate(ptr);
  197. }
  198. template <Allocator _allocator>
  199. class allocator_traits {
  200. public:
  201. using value_type = typename _allocator::value_type;
  202. static constexpr value_type* allocate(size_t count)
  203. {
  204. if (count == 0)
  205. return nullptr;
  206. return _allocator::allocate_memory(sizeof(value_type) * count);
  207. }
  208. template <typename... Args>
  209. static constexpr value_type* construct(value_type* ptr, Args&&... args)
  210. {
  211. new (ptr) value_type(std::forward<Args>(args)...);
  212. return ptr;
  213. }
  214. template <typename... Args>
  215. static constexpr value_type* allocate_and_construct(Args&&... args)
  216. {
  217. auto* ptr = allocate(1);
  218. construct(ptr, std::forward<Args>(args)...);
  219. return ptr;
  220. }
  221. static constexpr void deconstruct(value_type* ptr)
  222. {
  223. if (!ptr)
  224. return;
  225. ptr->~value_type();
  226. }
  227. static constexpr void deallocate(value_type* ptr)
  228. {
  229. if (!ptr)
  230. return;
  231. _allocator::deallocate_memory(ptr);
  232. }
  233. static constexpr void deconstruct_and_deallocate(value_type* ptr)
  234. {
  235. if (!ptr)
  236. return;
  237. deconstruct(ptr);
  238. deallocate(ptr);
  239. }
  240. };
  241. namespace __allocator {
  242. inline __allocator::brk_memory_allocator* m_palloc;
  243. inline void init_kernel_heap(void* start, size_t sz)
  244. {
  245. m_palloc = pnew<kernel_ident_allocator>(m_palloc, (uint8_t*)start, sz);
  246. }
  247. } // namespace __allocator
  248. template <typename T>
  249. class kernel_allocator {
  250. public:
  251. using value_type = T;
  252. static constexpr value_type* allocate_memory(size_t count)
  253. {
  254. return static_cast<value_type*>(__allocator::m_palloc->alloc(count));
  255. }
  256. static constexpr void deallocate_memory(value_type* ptr)
  257. {
  258. __allocator::m_palloc->free(ptr);
  259. }
  260. };
  261. template <typename T, template <typename> typename Allocator>
  262. struct allocator_adapter {
  263. using value_type = typename Allocator<T>::value_type;
  264. using propagate_on_container_move_assignment = std::true_type;
  265. constexpr allocator_adapter() = default;
  266. template <template <typename> typename UAlloc, typename U>
  267. constexpr allocator_adapter(const allocator_adapter<U, UAlloc>&)
  268. noexcept {}
  269. constexpr T* allocate(std::size_t n)
  270. { return types::allocator_traits<Allocator<T>>::allocate(n); }
  271. constexpr void deallocate(T* ptr, std::size_t)
  272. { return types::allocator_traits<Allocator<T>>::deallocate(ptr); }
  273. template <typename U>
  274. struct rebind { using other = allocator_adapter<U, Allocator>; };
  275. };
  276. } // namespace types