instance.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #pragma once
  2. #include "kernel.h"
  3. namespace pybind11 {
  4. struct type_info {
  5. std::string_view name;
  6. std::size_t size;
  7. std::size_t alignment;
  8. void (*destructor)(void*);
  9. const std::type_info* type;
  10. template <typename T>
  11. static type_info& of() {
  12. static_assert(!std::is_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
  13. "T must not be a reference type or const type.");
  14. static type_info info = {
  15. type_name<T>(),
  16. sizeof(T),
  17. alignof(T),
  18. [](void* ptr) {
  19. ((T*)ptr)->~T();
  20. operator delete (ptr);
  21. },
  22. &typeid(T),
  23. };
  24. return info;
  25. }
  26. };
  27. // all registered C++ class will be ensured as instance type.
  28. class instance {
  29. public:
  30. // use to record the type information of C++ class.
  31. private:
  32. enum Flag {
  33. None = 0,
  34. Own = 1 << 0, // if the instance is owned by C++ side.
  35. Ref = 1 << 1, // need to mark the parent object.
  36. };
  37. Flag flag;
  38. void* data;
  39. const type_info* type;
  40. pkpy::PyVar parent;
  41. public:
  42. instance() noexcept : flag(Flag::None), data(nullptr), type(nullptr), parent(nullptr) {}
  43. instance(const instance&) = delete;
  44. instance(instance&& other) noexcept : flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
  45. other.flag = Flag::None;
  46. other.data = nullptr;
  47. other.type = nullptr;
  48. other.parent = nullptr;
  49. }
  50. static pkpy::PyVar create(pkpy::Type type, const type_info* info) noexcept {
  51. instance instance;
  52. instance.type = info;
  53. instance.data = operator new (info->size);
  54. instance.flag = Flag::Own;
  55. return vm->heap.gcnew<pybind11::instance>(type, std::move(instance));
  56. }
  57. template <typename T>
  58. static pkpy::PyVar create(T&& value,
  59. pkpy::Type type,
  60. return_value_policy policy = return_value_policy::automatic_reference,
  61. pkpy::PyVar parent = nullptr) noexcept {
  62. using underlying_type = remove_cvref_t<T>;
  63. auto& _value = [&]() -> auto& {
  64. // note that, pybind11 will ignore the const qualifier.
  65. // in fact, try to modify a const value will result in undefined behavior.
  66. if constexpr(std::is_pointer_v<underlying_type>) {
  67. return *reinterpret_cast<underlying_type*>(value);
  68. } else {
  69. return const_cast<underlying_type&>(value);
  70. }
  71. }();
  72. using primary = std::remove_pointer_t<underlying_type>;
  73. instance instance;
  74. instance.type = &type_info::of<primary>();
  75. if(policy == return_value_policy::take_ownership) {
  76. instance.data = &_value;
  77. instance.flag = Flag::Own;
  78. } else if(policy == return_value_policy::copy) {
  79. if constexpr(std::is_copy_constructible_v<primary>) {
  80. instance.data = ::new auto(_value);
  81. instance.flag = Flag::Own;
  82. } else {
  83. std::string msg = "cannot use copy policy on non-copyable type: ";
  84. msg += type_name<primary>();
  85. vm->RuntimeError(msg);
  86. }
  87. } else if(policy == return_value_policy::move) {
  88. if constexpr(std::is_move_constructible_v<primary>) {
  89. instance.data = ::new auto(std::move(_value));
  90. instance.flag = Flag::Own;
  91. } else {
  92. std::string msg = "cannot use move policy on non-moveable type: ";
  93. msg += type_name<primary>();
  94. vm->RuntimeError(msg);
  95. }
  96. } else if(policy == return_value_policy::reference) {
  97. instance.data = &_value;
  98. instance.flag = Flag::None;
  99. } else if(policy == return_value_policy::reference_internal) {
  100. instance.data = &_value;
  101. instance.flag = Flag::Ref;
  102. instance.parent = parent;
  103. }
  104. return vm->heap.gcnew<pybind11::instance>(type, std::move(instance));
  105. }
  106. ~instance() {
  107. if(flag & Flag::Own) { type->destructor(data); }
  108. }
  109. template <typename T>
  110. T& _as() noexcept {
  111. return *static_cast<T*>(data);
  112. }
  113. #if PK_VERSION_MAJOR == 2
  114. void _gc_mark(pkpy::VM* vm) const noexcept {
  115. if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
  116. }
  117. #else
  118. void _gc_mark() const noexcept {
  119. if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
  120. }
  121. #endif
  122. };
  123. } // namespace pybind11