class.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #pragma once
  2. #include "module.h"
  3. #include "type_traits.h"
  4. namespace pkbind {
  5. struct dynamic_attr {};
  6. template <typename T, typename Base = void>
  7. class class_ : public type {
  8. protected:
  9. handle m_scope;
  10. public:
  11. using type::type;
  12. using underlying_type = T;
  13. template <typename... Args>
  14. class_(handle scope, const char* name, const Args&... args) :
  15. type(py_newtype(name,
  16. std::is_same_v<Base, void> ? tp_object : type::of<Base>().index(),
  17. scope.ptr(),
  18. [](void* data) {
  19. static_cast<instance*>(data)->~instance();
  20. })),
  21. m_scope(scope) {
  22. m_type_map.try_emplace(typeid(T), this->index());
  23. auto& info = type_info::of<T>();
  24. info.name = name;
  25. py_newfunction(
  26. py_tpgetmagic(this->index(), py_MagicNames::__new__),
  27. "__new__(type, *args, **kwargs)",
  28. [](int, py_Ref stack) {
  29. auto cls = py_offset(stack, 0);
  30. [[maybe_unused]] auto args = py_offset(stack, 1);
  31. [[maybe_unused]] auto kwargs = py_offset(stack, 2);
  32. auto info = &type_info::of<T>();
  33. int slot = ((std::is_same_v<dynamic_attr, Args> || ...) ? -1 : 0);
  34. void* data =
  35. py_newobject(py_retval(), steal<type>(cls).index(), slot, sizeof(instance));
  36. new (data) instance{instance::Flag::Own, operator new (info->size), info};
  37. return true;
  38. },
  39. nullptr,
  40. 0);
  41. }
  42. /// bind constructor
  43. template <typename... Args, typename... Extra>
  44. class_& def(impl::constructor<Args...>, const Extra&... extra) {
  45. if constexpr(!std::is_constructible_v<T, Args...>) {
  46. static_assert(std::is_constructible_v<T, Args...>, "Invalid constructor arguments");
  47. } else {
  48. impl::bind_function<true, false>(
  49. *this,
  50. "__init__",
  51. [](T* self, Args... args) {
  52. new (self) T(args...);
  53. },
  54. extra...);
  55. return *this;
  56. }
  57. }
  58. template <typename Fn, typename... Extra>
  59. class_& def(impl::factory<Fn> factory, const Extra&... extra) {
  60. using ret = callable_return_t<Fn>;
  61. if constexpr(!std::is_same_v<T, ret>) {
  62. static_assert(std::is_same_v<T, ret>, "Factory function must return the class type");
  63. } else {
  64. impl::bind_function<true, false>(*this, "__init__", factory.make(), extra...);
  65. return *this;
  66. }
  67. }
  68. /// bind member function
  69. template <typename Fn, typename... Extra>
  70. class_& def(const char* name, Fn&& f, const Extra&... extra) {
  71. using first = remove_cvref_t<std::tuple_element_t<0, callable_args_t<remove_cvref_t<Fn>>>>;
  72. constexpr bool is_first_base_of_v = std::is_base_of_v<first, T> || std::is_same_v<first, T>;
  73. if constexpr(!is_first_base_of_v) {
  74. static_assert(
  75. is_first_base_of_v,
  76. "If you want to bind member function, the first argument must be the base class");
  77. } else {
  78. impl::bind_function<true, false>(*this, name, std::forward<Fn>(f), extra...);
  79. }
  80. return *this;
  81. }
  82. /// bind operators
  83. template <typename Operator, typename... Extras>
  84. class_& def(Operator op, const Extras&... extras) {
  85. op.execute(*this, extras...);
  86. return *this;
  87. }
  88. /// bind static function
  89. template <typename Fn, typename... Extra>
  90. class_& def_static(const char* name, Fn&& f, const Extra&... extra) {
  91. impl::bind_function<false, true>(*this, name, std::forward<Fn>(f), extra...);
  92. return *this;
  93. }
  94. template <typename MP, typename... Extras>
  95. class_& def_readwrite(const char* name, MP mp, const Extras&... extras) {
  96. if constexpr(!std::is_member_object_pointer_v<MP>) {
  97. static_assert(std::is_member_object_pointer_v<MP>,
  98. "def_readwrite only supports pointer to data member");
  99. } else {
  100. impl::bind_property(
  101. *this,
  102. name,
  103. [mp](class_type_t<MP>& self) -> auto& {
  104. return self.*mp;
  105. },
  106. [mp](class_type_t<MP>& self, const member_type_t<MP>& value) {
  107. self.*mp = value;
  108. },
  109. extras...);
  110. }
  111. return *this;
  112. }
  113. template <typename MP, typename... Extras>
  114. class_& def_readonly(const char* name, MP mp, const Extras&... extras) {
  115. if constexpr(!std::is_member_object_pointer_v<MP>) {
  116. static_assert(std::is_member_object_pointer_v<MP>,
  117. "def_readonly only supports pointer to data member");
  118. } else {
  119. impl::bind_property(
  120. *this,
  121. name,
  122. [mp](class_type_t<MP>& self) -> auto& {
  123. return self.*mp;
  124. },
  125. nullptr,
  126. extras...);
  127. }
  128. return *this;
  129. }
  130. template <typename Getter, typename Setter, typename... Extras>
  131. class_& def_property(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
  132. impl::bind_property(*this,
  133. name,
  134. std::forward<Getter>(g),
  135. std::forward<Setter>(s),
  136. extras...);
  137. return *this;
  138. }
  139. template <typename Getter, typename... Extras>
  140. class_& def_property_readonly(const char* name, Getter&& mp, const Extras&... extras) {
  141. impl::bind_property(*this, name, std::forward<Getter>(mp), nullptr, extras...);
  142. return *this;
  143. }
  144. template <typename Var, typename... Extras>
  145. class_& def_readwrite_static(const char* name, Var& mp, const Extras&... extras) {
  146. static_assert(
  147. dependent_false<Var>,
  148. "define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
  149. return *this;
  150. }
  151. template <typename Var, typename... Extras>
  152. class_& def_readonly_static(const char* name, Var& mp, const Extras&... extras) {
  153. static_assert(
  154. dependent_false<Var>,
  155. "define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
  156. return *this;
  157. }
  158. template <typename Getter, typename Setter, typename... Extras>
  159. class_& def_property_static(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
  160. static_assert(
  161. dependent_false<Getter>,
  162. "define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
  163. return *this;
  164. }
  165. };
  166. template <typename T, typename... Others>
  167. class enum_ : public class_<T, Others...> {
  168. std::vector<std::pair<const char*, object>> m_values;
  169. public:
  170. using Base = class_<T, Others...>;
  171. template <typename... Args>
  172. enum_(const handle& scope, const char* name, Args&&... args) :
  173. class_<T, Others...>(scope, name, std::forward<Args>(args)...) {
  174. Base::def(init([](int value) {
  175. return static_cast<T>(value);
  176. }));
  177. Base::def("__eq__", [](T& self, T& other) {
  178. return self == other;
  179. });
  180. Base::def_property_readonly("value", [](T& self) {
  181. return int_(static_cast<std::underlying_type_t<T>>(self));
  182. });
  183. }
  184. enum_& value(const char* name, T value) {
  185. auto var = pkbind::cast(value, return_value_policy::copy);
  186. setattr(*this, name, var);
  187. m_values.emplace_back(name, std::move(var));
  188. return *this;
  189. }
  190. enum_& export_values() {
  191. for(auto& [name, value]: m_values) {
  192. setattr(Base::m_scope, name, value);
  193. }
  194. return *this;
  195. }
  196. };
  197. } // namespace pkbind