kernel.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #pragma once
  2. #include <array>
  3. #include <vector>
  4. #include <string>
  5. #include <cstdlib>
  6. #include <cstring>
  7. #include <cassert>
  8. #include <optional>
  9. #include <typeindex>
  10. #include <stdexcept>
  11. #include <unordered_map>
  12. #include "pocketpy.h"
  13. #include "type_traits.h"
  14. namespace pkbind {
  15. class handle;
  16. struct action {
  17. using function = void (*)();
  18. inline static std::vector<function> starts;
  19. static void initialize() noexcept {
  20. for(auto func: starts) {
  21. func();
  22. }
  23. }
  24. // register a function to be called at the start of the vm.
  25. static void register_start(function func) { starts.push_back(func); }
  26. };
  27. /// hold the object long time.
  28. struct object_pool {
  29. inline static int cache = -1;
  30. inline static py_Ref pool = nullptr;
  31. inline static std::vector<int>* indices_ = nullptr;
  32. struct object_ref {
  33. py_Ref data;
  34. int index;
  35. };
  36. static void initialize(int size) noexcept {
  37. pool = py_sysr1();
  38. py_newtuple(pool, size);
  39. indices_ = new std::vector<int>(size, 0);
  40. }
  41. static void finalize() noexcept {
  42. delete indices_;
  43. indices_ = nullptr;
  44. }
  45. /// alloc an object from pool, note that the object is uninitialized.
  46. static object_ref alloc() {
  47. if(!indices_) { initialize(1024); }
  48. auto& indices = *indices_;
  49. if(cache != -1) {
  50. auto index = cache;
  51. cache = -1;
  52. indices[index] = 1;
  53. return {py_tuple_getitem(pool, index), index};
  54. }
  55. for(int i = 0; i < indices.size(); ++i) {
  56. if(indices[i] == 0) {
  57. indices[i] = 1;
  58. return {py_tuple_getitem(pool, i), i};
  59. }
  60. }
  61. throw std::runtime_error("object pool is full");
  62. }
  63. /// alloc an object from pool, the object is initialized with ref.
  64. static object_ref realloc(py_Ref ref) {
  65. auto result = alloc();
  66. py_assign(result.data, ref);
  67. return result;
  68. }
  69. static void inc_ref(object_ref ref) {
  70. if(!indices_) { return; }
  71. if(ref.data == py_tuple_getitem(pool, ref.index)) {
  72. auto& indices = *indices_;
  73. indices[ref.index] += 1;
  74. } else {
  75. throw std::runtime_error("object_ref is invalid");
  76. }
  77. }
  78. static void dec_ref(object_ref ref) {
  79. if(!indices_) { return; }
  80. if(ref.data == py_tuple_getitem(pool, ref.index)) {
  81. auto& indices = *indices_;
  82. indices[ref.index] -= 1;
  83. assert(indices[ref.index] >= 0 && "ref count is negative");
  84. if(indices[ref.index] == 0) { cache = ref.index; }
  85. } else {
  86. throw std::runtime_error("object_ref is invalid");
  87. }
  88. }
  89. };
  90. template <typename T>
  91. class lazy {
  92. public:
  93. lazy(void (*init)(T&)) : init(init) {}
  94. operator T& () {
  95. if(!initialized) {
  96. if(init) { init(value); }
  97. initialized = true;
  98. }
  99. return value;
  100. }
  101. T& operator* () { return static_cast<T&>(*this); }
  102. void reset() { initialized = false; }
  103. private:
  104. T value;
  105. bool initialized = false;
  106. void (*init)(T&) = nullptr;
  107. };
  108. } // namespace pkbind