memory.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #pragma once
  2. #include "common.h"
  3. struct PyObject;
  4. namespace pkpy{
  5. template<typename T>
  6. struct SpAllocator {
  7. template<typename U>
  8. inline static int* alloc(){
  9. return (int*)malloc(sizeof(int) + sizeof(U));
  10. }
  11. inline static void dealloc(int* counter){
  12. ((T*)(counter + 1))->~T();
  13. free(counter);
  14. }
  15. };
  16. template <typename T>
  17. struct shared_ptr {
  18. union {
  19. int* counter;
  20. i64 bits;
  21. };
  22. #define _t() (T*)(counter + 1)
  23. #define _inc_counter() if(!is_tagged() && counter) ++(*counter)
  24. #define _dec_counter() if(!is_tagged() && counter && --(*counter) == 0) SpAllocator<T>::dealloc(counter)
  25. public:
  26. shared_ptr() : counter(nullptr) {}
  27. shared_ptr(int* counter) : counter(counter) {}
  28. shared_ptr(const shared_ptr& other) : counter(other.counter) {
  29. _inc_counter();
  30. }
  31. shared_ptr(shared_ptr&& other) noexcept : counter(other.counter) {
  32. other.counter = nullptr;
  33. }
  34. ~shared_ptr() { _dec_counter(); }
  35. bool operator==(const shared_ptr& other) const { return counter == other.counter; }
  36. bool operator!=(const shared_ptr& other) const { return counter != other.counter; }
  37. bool operator<(const shared_ptr& other) const { return counter < other.counter; }
  38. bool operator>(const shared_ptr& other) const { return counter > other.counter; }
  39. bool operator<=(const shared_ptr& other) const { return counter <= other.counter; }
  40. bool operator>=(const shared_ptr& other) const { return counter >= other.counter; }
  41. bool operator==(std::nullptr_t) const { return counter == nullptr; }
  42. bool operator!=(std::nullptr_t) const { return counter != nullptr; }
  43. shared_ptr& operator=(const shared_ptr& other) {
  44. _dec_counter();
  45. counter = other.counter;
  46. _inc_counter();
  47. return *this;
  48. }
  49. shared_ptr& operator=(shared_ptr&& other) noexcept {
  50. _dec_counter();
  51. counter = other.counter;
  52. other.counter = nullptr;
  53. return *this;
  54. }
  55. T& operator*() const { return *_t(); }
  56. T* operator->() const { return _t(); }
  57. T* get() const { return _t(); }
  58. int use_count() const {
  59. if(is_tagged()) return 1;
  60. return counter ? *counter : 0;
  61. }
  62. void reset(){
  63. _dec_counter();
  64. counter = nullptr;
  65. }
  66. inline constexpr bool is_tagged() const {
  67. if constexpr(!std::is_same_v<T, PyObject>) return false;
  68. return (bits & 0b11) != 0b00;
  69. }
  70. inline bool is_tag_00() const { return (bits & 0b11) == 0b00; }
  71. inline bool is_tag_01() const { return (bits & 0b11) == 0b01; }
  72. inline bool is_tag_10() const { return (bits & 0b11) == 0b10; }
  73. inline bool is_tag_11() const { return (bits & 0b11) == 0b11; }
  74. };
  75. #undef _t
  76. #undef _inc_counter
  77. #undef _dec_counter
  78. template <typename T, typename U, typename... Args>
  79. shared_ptr<T> make_shared(Args&&... args) {
  80. static_assert(std::is_base_of_v<T, U>, "U must be derived from T");
  81. static_assert(std::has_virtual_destructor_v<T>, "T must have virtual destructor");
  82. static_assert(!std::is_same_v<T, PyObject> || (!std::is_same_v<U, i64> && !std::is_same_v<U, f64>));
  83. int* p = SpAllocator<T>::template alloc<U>(); *p = 1;
  84. new(p+1) U(std::forward<Args>(args)...);
  85. return shared_ptr<T>(p);
  86. }
  87. template <typename T, typename... Args>
  88. shared_ptr<T> make_shared(Args&&... args) {
  89. int* p = SpAllocator<T>::template alloc<T>(); *p = 1;
  90. new(p+1) T(std::forward<Args>(args)...);
  91. return shared_ptr<T>(p);
  92. }
  93. };
  94. static_assert(sizeof(i64) == sizeof(int*));
  95. static_assert(sizeof(f64) == sizeof(int*));
  96. static_assert(sizeof(pkpy::shared_ptr<PyObject>) == sizeof(int*));
  97. static_assert(std::numeric_limits<float>::is_iec559);
  98. static_assert(std::numeric_limits<double>::is_iec559);
  99. template<typename T, int __Bucket, int __BucketSize=32>
  100. struct SmallArrayPool {
  101. std::deque<T*> buckets[__Bucket+1];
  102. T* alloc(int n){
  103. if(n == 0) return nullptr;
  104. if(n > __Bucket || buckets[n].empty()){
  105. return new T[n];
  106. }else{
  107. T* p = buckets[n].back();
  108. buckets[n].pop_back();
  109. return p;
  110. }
  111. }
  112. void dealloc(T* p, int n){
  113. if(n == 0) return;
  114. if(n > __Bucket){
  115. delete[] p;
  116. }else{
  117. buckets[n].push_back(p);
  118. }
  119. }
  120. ~SmallArrayPool(){
  121. for(int i=1; i<=__Bucket; i++){
  122. for(auto p: buckets[i]) delete[] p;
  123. }
  124. }
  125. };
  126. typedef pkpy::shared_ptr<PyObject> PyVar;
  127. typedef PyVar PyVarOrNull;
  128. typedef PyVar PyVarRef;