General Purpose library for Freestanding C++ and POSIX systems
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

215 рядки
4.2 KiB

4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
4 роки тому
  1. #pragma once
  2. #include "gp/exception.hpp"
  3. #include "gp/algorithm/tmp_manip.hpp"
  4. #include "gp/algorithm/move.hpp"
  5. namespace gp{
  6. template <typename>
  7. class function;
  8. template <typename ret, typename ...args>
  9. class function<ret(args...)>{
  10. struct virtual_callable
  11. {
  12. virtual void inplace_move(char*) = 0;
  13. virtual virtual_callable* all_copy() = 0;
  14. virtual void inplace_copy(char*) = 0;
  15. virtual virtual_callable* all_move() = 0;
  16. virtual ~virtual_callable() = default;
  17. virtual ret operator() (args...) = 0;
  18. };
  19. template<typename fn>
  20. class callable final : public virtual_callable{
  21. typename gp::remove_reference<fn>::type internal_representation;
  22. public:
  23. callable(const fn func)
  24. : internal_representation{gp::move(func)}
  25. {}
  26. callable(callable&) = default;
  27. callable(callable&&) = default;
  28. virtual ~callable() override = default;
  29. virtual void inplace_copy(char* ptr) override {
  30. new(ptr) callable(*this);
  31. }
  32. virtual virtual_callable* all_copy() override {
  33. return new callable(*this);
  34. }
  35. virtual void inplace_move(char* ptr) override {
  36. new(ptr) callable(gp::move(*this));
  37. }
  38. virtual virtual_callable* all_move() override {
  39. return new callable(gp::move(*this));
  40. }
  41. ret operator() (args... arg_list) override
  42. {
  43. return internal_representation(arg_list...);
  44. }
  45. };
  46. // tweak a way to store a size in there for trivial copy
  47. enum state_t : uint8_t{
  48. INACTIVE = 0,
  49. ACTIVE = 1,
  50. NO_SOO = 0,
  51. SOO = 2
  52. };
  53. state_t state{};
  54. union{
  55. virtual_callable* functor = nullptr;
  56. char inplace[12];
  57. } self;
  58. public:
  59. template <typename T>
  60. function& operator=(T& t)
  61. {
  62. if(state & ACTIVE)
  63. {
  64. if(state & SOO)
  65. {
  66. ((virtual_callable*)self.inplace)->~virtual_callable();
  67. }
  68. else
  69. {
  70. delete self.functor;
  71. }
  72. }
  73. if(!(t.state & ACTIVE))
  74. {
  75. state = INACTIVE;
  76. return;
  77. }
  78. if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
  79. if constexpr (sizeof(callable<T>) <= sizeof(self))
  80. {
  81. new((void*)self.inplace) callable<T>(t);
  82. state = (state_t)(ACTIVE | SOO);
  83. }
  84. else
  85. {
  86. self.functor = new callable<T>(t);
  87. state = (state_t)(ACTIVE | NO_SOO);
  88. }
  89. } else {
  90. if(t.state & SOO)
  91. {
  92. auto& ref = t.self.functor;
  93. ref->inplace_copy((char*)&self);
  94. state = (state_t)(ACTIVE | SOO);
  95. }
  96. else
  97. {
  98. self.functor = t.self.functor->all_copy();
  99. state = (state_t)(ACTIVE | NO_SOO);
  100. }
  101. }
  102. }
  103. function()
  104. {
  105. state = INACTIVE;
  106. }
  107. template<typename T>
  108. function<>(T& t)
  109. {
  110. if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
  111. if constexpr (sizeof(callable<T>) <= sizeof(self))
  112. {
  113. new((void*)self.inplace) callable<T>(t);
  114. state = (state_t)(ACTIVE | SOO);
  115. }
  116. else
  117. {
  118. self.functor = new callable<T>(t);
  119. state = (state_t)(ACTIVE | NO_SOO);
  120. }
  121. } else {
  122. if(t.state & SOO)
  123. {
  124. t.self.functor->inplace_copy(self.inplace);
  125. state = (state_t)(ACTIVE | SOO);
  126. }
  127. else
  128. {
  129. self.functor = t.self.functor->all_copy();
  130. state = (state_t)(ACTIVE | NO_SOO);
  131. }
  132. }
  133. }
  134. template <typename T>
  135. function(T&& t)
  136. {
  137. if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
  138. if constexpr (sizeof(callable<T>) <= sizeof(self))
  139. {
  140. new((void*)self.inplace) callable<T>(gp::move(t));
  141. state = (state_t)(ACTIVE | SOO);
  142. }
  143. else
  144. {
  145. self.functor = new callable<T>(gp::move(t));
  146. state = (state_t)(ACTIVE | NO_SOO);
  147. }
  148. } else {
  149. if(t.state & SOO)
  150. {
  151. auto& ref = t.self.functor;
  152. ref->inplace_move((char*)&self);
  153. state = (state_t)(ACTIVE | SOO);
  154. }
  155. else
  156. {
  157. self.functor = t.self.functor->all_move();
  158. state = (state_t)(ACTIVE | NO_SOO);
  159. }
  160. }
  161. }
  162. ret operator()(args... arg_list) const {
  163. if constexpr (gp_config::has_exceptions)
  164. {
  165. if(!(state & ACTIVE))
  166. {
  167. throw bad_functor{};
  168. }
  169. }
  170. if(state & SOO)
  171. {
  172. return (*(virtual_callable*)&self)(arg_list...);
  173. }
  174. else
  175. {
  176. return (*self.functor)(arg_list...);
  177. }
  178. }
  179. ~function()
  180. {
  181. if(state & ACTIVE)
  182. {
  183. if(state & SOO)
  184. {
  185. ((virtual_callable*)&self)->~virtual_callable();
  186. }
  187. else
  188. {
  189. delete self.functor;
  190. }
  191. }
  192. }
  193. };
  194. }