memory.h 8.6 KB

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