memory.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #pragma once
  2. #include "common.h"
  3. namespace pkpy{
  4. struct LinkedListNode{
  5. LinkedListNode* prev;
  6. LinkedListNode* next;
  7. };
  8. template<typename T>
  9. struct DoubleLinkedList{
  10. static_assert(std::is_base_of_v<LinkedListNode, T>);
  11. int _size;
  12. LinkedListNode head;
  13. LinkedListNode tail;
  14. DoubleLinkedList(): _size(0){
  15. head.prev = nullptr;
  16. head.next = &tail;
  17. tail.prev = &head;
  18. tail.next = nullptr;
  19. }
  20. void push_back(T* node){
  21. node->prev = tail.prev;
  22. node->next = &tail;
  23. tail.prev->next = node;
  24. tail.prev = node;
  25. _size++;
  26. }
  27. void push_front(T* node){
  28. node->prev = &head;
  29. node->next = head.next;
  30. head.next->prev = node;
  31. head.next = node;
  32. _size++;
  33. }
  34. void pop_back(){
  35. #if PK_DEBUG_MEMORY_POOL
  36. if(empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list");
  37. #endif
  38. tail.prev->prev->next = &tail;
  39. tail.prev = tail.prev->prev;
  40. _size--;
  41. }
  42. void pop_front(){
  43. #if PK_DEBUG_MEMORY_POOL
  44. if(empty()) throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list");
  45. #endif
  46. head.next->next->prev = &head;
  47. head.next = head.next->next;
  48. _size--;
  49. }
  50. T* back() const {
  51. #if PK_DEBUG_MEMORY_POOL
  52. if(empty()) throw std::runtime_error("DoubleLinkedList::back() called on empty list");
  53. #endif
  54. return static_cast<T*>(tail.prev);
  55. }
  56. T* front() const {
  57. #if PK_DEBUG_MEMORY_POOL
  58. if(empty()) throw std::runtime_error("DoubleLinkedList::front() called on empty list");
  59. #endif
  60. return static_cast<T*>(head.next);
  61. }
  62. void erase(T* node){
  63. #if PK_DEBUG_MEMORY_POOL
  64. if(empty()) throw std::runtime_error("DoubleLinkedList::erase() called on empty list");
  65. LinkedListNode* n = head.next;
  66. while(n != &tail){
  67. if(n == node) break;
  68. n = n->next;
  69. }
  70. if(n != node) throw std::runtime_error("DoubleLinkedList::erase() called on node not in the list");
  71. #endif
  72. node->prev->next = node->next;
  73. node->next->prev = node->prev;
  74. _size--;
  75. }
  76. // void move_all_back(DoubleLinkedList<T>& other){
  77. // if(other.empty()) return;
  78. // other.tail.prev->next = &tail;
  79. // tail.prev->next = other.head.next;
  80. // other.head.next->prev = tail.prev;
  81. // tail.prev = other.tail.prev;
  82. // _size += other._size;
  83. // other.head.next = &other.tail;
  84. // other.tail.prev = &other.head;
  85. // other._size = 0;
  86. // }
  87. bool empty() const {
  88. #if PK_DEBUG_MEMORY_POOL
  89. if(size() == 0){
  90. if(head.next != &tail || tail.prev != &head){
  91. throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty");
  92. }
  93. return true;
  94. }
  95. #endif
  96. return _size == 0;
  97. }
  98. int size() const { return _size; }
  99. template<typename Func>
  100. void apply(Func func){
  101. LinkedListNode* p = head.next;
  102. while(p != &tail){
  103. LinkedListNode* next = p->next;
  104. func(static_cast<T*>(p));
  105. p = next;
  106. }
  107. }
  108. };
  109. template<int __BlockSize=128>
  110. struct MemoryPool{
  111. static const size_t __MaxBlocks = 256*1024 / __BlockSize;
  112. struct Block{
  113. void* arena;
  114. char data[__BlockSize];
  115. };
  116. struct Arena: LinkedListNode{
  117. Block _blocks[__MaxBlocks];
  118. Block* _free_list[__MaxBlocks];
  119. int _free_list_size;
  120. bool dirty;
  121. Arena(): _free_list_size(__MaxBlocks), dirty(false){
  122. for(int i=0; i<__MaxBlocks; i++){
  123. _blocks[i].arena = this;
  124. _free_list[i] = &_blocks[i];
  125. }
  126. }
  127. bool empty() const { return _free_list_size == 0; }
  128. bool full() const { return _free_list_size == __MaxBlocks; }
  129. size_t allocated_size() const{
  130. return __BlockSize * (__MaxBlocks - _free_list_size);
  131. }
  132. Block* alloc(){
  133. #if PK_DEBUG_MEMORY_POOL
  134. if(empty()) throw std::runtime_error("Arena::alloc() called on empty arena");
  135. #endif
  136. _free_list_size--;
  137. return _free_list[_free_list_size];
  138. }
  139. void dealloc(Block* block){
  140. #if PK_DEBUG_MEMORY_POOL
  141. if(full()) throw std::runtime_error("Arena::dealloc() called on full arena");
  142. #endif
  143. _free_list[_free_list_size] = block;
  144. _free_list_size++;
  145. }
  146. };
  147. MemoryPool() = default;
  148. MemoryPool(const MemoryPool&) = delete;
  149. MemoryPool& operator=(const MemoryPool&) = delete;
  150. MemoryPool(MemoryPool&&) = delete;
  151. MemoryPool& operator=(MemoryPool&&) = delete;
  152. DoubleLinkedList<Arena> _arenas;
  153. DoubleLinkedList<Arena> _empty_arenas;
  154. template<typename __T>
  155. void* alloc() { return alloc(sizeof(__T)); }
  156. void* alloc(size_t size){
  157. PK_GLOBAL_SCOPE_LOCK();
  158. #if PK_DEBUG_NO_MEMORY_POOL
  159. return malloc(size);
  160. #endif
  161. if(size > __BlockSize){
  162. void* p = malloc(sizeof(void*) + size);
  163. memset(p, 0, sizeof(void*));
  164. return (char*)p + sizeof(void*);
  165. }
  166. if(_arenas.empty()){
  167. // std::cout << _arenas.size() << ',' << _empty_arenas.size() << ',' << _full_arenas.size() << std::endl;
  168. _arenas.push_back(new Arena());
  169. }
  170. Arena* arena = _arenas.back();
  171. void* p = arena->alloc()->data;
  172. if(arena->empty()){
  173. _arenas.pop_back();
  174. arena->dirty = true;
  175. _empty_arenas.push_back(arena);
  176. }
  177. return p;
  178. }
  179. void dealloc(void* p){
  180. PK_GLOBAL_SCOPE_LOCK();
  181. #if PK_DEBUG_NO_MEMORY_POOL
  182. free(p);
  183. return;
  184. #endif
  185. #if PK_DEBUG_MEMORY_POOL
  186. if(p == nullptr) throw std::runtime_error("MemoryPool::dealloc() called on nullptr");
  187. #endif
  188. Block* block = (Block*)((char*)p - sizeof(void*));
  189. if(block->arena == nullptr){
  190. free(block);
  191. }else{
  192. Arena* arena = (Arena*)block->arena;
  193. if(arena->empty()){
  194. _empty_arenas.erase(arena);
  195. _arenas.push_front(arena);
  196. arena->dealloc(block);
  197. }else{
  198. arena->dealloc(block);
  199. if(arena->full() && arena->dirty){
  200. _arenas.erase(arena);
  201. delete arena;
  202. }
  203. }
  204. }
  205. }
  206. size_t allocated_size() {
  207. size_t n = 0;
  208. _arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); });
  209. _empty_arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); });
  210. return n;
  211. }
  212. ~MemoryPool(){
  213. _arenas.apply([](Arena* arena){ delete arena; });
  214. _empty_arenas.apply([](Arena* arena){ delete arena; });
  215. }
  216. };
  217. inline MemoryPool<64> pool64;
  218. inline MemoryPool<128> pool128;
  219. template <typename T>
  220. struct shared_ptr {
  221. int* counter;
  222. T* _t() const noexcept { return (T*)(counter + 1); }
  223. void _inc_counter() { if(counter) ++(*counter); }
  224. void _dec_counter() { if(counter && --(*counter) == 0) {((T*)(counter + 1))->~T(); pool128.dealloc(counter);} }
  225. public:
  226. shared_ptr() : counter(nullptr) {}
  227. shared_ptr(int* counter) : counter(counter) {}
  228. shared_ptr(const shared_ptr& other) : counter(other.counter) {
  229. _inc_counter();
  230. }
  231. shared_ptr(shared_ptr&& other) noexcept : counter(other.counter) {
  232. other.counter = nullptr;
  233. }
  234. ~shared_ptr() { _dec_counter(); }
  235. bool operator==(const shared_ptr& other) const { return counter == other.counter; }
  236. bool operator!=(const shared_ptr& other) const { return counter != other.counter; }
  237. bool operator<(const shared_ptr& other) const { return counter < other.counter; }
  238. bool operator>(const shared_ptr& other) const { return counter > other.counter; }
  239. bool operator<=(const shared_ptr& other) const { return counter <= other.counter; }
  240. bool operator>=(const shared_ptr& other) const { return counter >= other.counter; }
  241. bool operator==(std::nullptr_t) const { return counter == nullptr; }
  242. bool operator!=(std::nullptr_t) const { return counter != nullptr; }
  243. shared_ptr& operator=(const shared_ptr& other) {
  244. _dec_counter();
  245. counter = other.counter;
  246. _inc_counter();
  247. return *this;
  248. }
  249. shared_ptr& operator=(shared_ptr&& other) noexcept {
  250. _dec_counter();
  251. counter = other.counter;
  252. other.counter = nullptr;
  253. return *this;
  254. }
  255. T& operator*() const { return *_t(); }
  256. T* operator->() const { return _t(); }
  257. T* get() const { return _t(); }
  258. int use_count() const {
  259. return counter ? *counter : 0;
  260. }
  261. void reset(){
  262. _dec_counter();
  263. counter = nullptr;
  264. }
  265. };
  266. template <typename T, typename... Args>
  267. shared_ptr<T> make_sp(Args&&... args) {
  268. int* p = (int*)pool128.alloc(sizeof(int) + sizeof(T));
  269. *p = 1;
  270. new(p+1) T(std::forward<Args>(args)...);
  271. return shared_ptr<T>(p);
  272. }
  273. }; // namespace pkpy