instance.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #pragma once
  2. #include "accessor.h"
  3. namespace pkbind {
  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. delete static_cast<T*>(ptr);
  20. },
  21. &typeid(T),
  22. };
  23. return info;
  24. }
  25. };
  26. // all registered C++ class will be ensured as instance type.
  27. struct instance {
  28. // use to record the type information of C++ class.
  29. enum Flag {
  30. None = 0,
  31. Own = 1 << 0, // if the instance is owned by C++ side.
  32. Ref = 1 << 1, // need to mark the parent object.
  33. };
  34. Flag flag;
  35. void* data;
  36. const type_info* info;
  37. object parent;
  38. public:
  39. template <typename Value>
  40. static object create(type type, Value&& value_, handle parent_, return_value_policy policy) {
  41. using underlying_type = remove_cvref_t<Value>;
  42. auto& value = [&]() -> auto& {
  43. // note that, pybind11 will ignore the const qualifier.
  44. // in fact, try to modify a const value will result in undefined behavior.
  45. if constexpr(std::is_pointer_v<underlying_type>) {
  46. return *reinterpret_cast<underlying_type*>(value_);
  47. } else {
  48. return const_cast<underlying_type&>(value_);
  49. }
  50. }();
  51. using primary = std::remove_pointer_t<underlying_type>;
  52. auto info = &type_info::of<primary>();
  53. void* data = nullptr;
  54. Flag flag = Flag::None;
  55. object parent;
  56. if(policy == return_value_policy::take_ownership) {
  57. data = &value;
  58. flag = Flag::Own;
  59. } else if(policy == return_value_policy::copy) {
  60. if constexpr(std::is_copy_constructible_v<primary>) {
  61. data = new auto(value);
  62. flag = Flag::Own;
  63. } else {
  64. std::string msg = "cannot use copy policy on non-copyable type: ";
  65. msg += type_name<primary>();
  66. throw std::runtime_error(msg);
  67. }
  68. } else if(policy == return_value_policy::move) {
  69. if constexpr(std::is_move_constructible_v<primary>) {
  70. data = new auto(std::move(value));
  71. flag = Flag::Own;
  72. } else {
  73. std::string msg = "cannot use move policy on non-moveable type: ";
  74. msg += type_name<primary>();
  75. throw std::runtime_error(msg);
  76. }
  77. } else if(policy == return_value_policy::reference) {
  78. data = &value;
  79. flag = Flag::None;
  80. } else if(policy == return_value_policy::reference_internal) {
  81. data = &value;
  82. flag = Flag::Ref;
  83. parent = borrow(parent_);
  84. }
  85. object result(object::alloc_t{});
  86. void* temp = py_newobject(result.ptr(), type.index(), 1, sizeof(instance));
  87. new (temp) instance{flag, data, info, std::move(parent)};
  88. return result;
  89. }
  90. ~instance() {
  91. if(flag & Flag::Own) {
  92. info->destructor(data);
  93. }
  94. }
  95. template <typename T>
  96. T& as() noexcept {
  97. return *static_cast<T*>(data);
  98. }
  99. };
  100. } // namespace pkbind