instance.h 5.3 KB

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