General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
7.2 KiB

  1. #pragma once
  2. #include "gp/exception.hpp"
  3. #include "gp/algorithm/modifiers.hpp"
  4. #include "gp/algorithm/move.hpp"
  5. #include "gp/algorithm/tmp_manip.hpp"
  6. #include "gp/allocator/allocator.hpp"
  7. namespace gp{
  8. template <typename fn>
  9. class function;
  10. template <typename ret, typename ...args>
  11. class function<ret(args...)>{
  12. using fn_ptr = char*;
  13. using invoke_fn_t = ret (*)(fn_ptr, args&&...);
  14. using condestruct_fn_t = void (*) (fn_ptr, fn_ptr);
  15. gp::reference_wrapper<allocator> alloc;
  16. invoke_fn_t invokator;
  17. condestruct_fn_t condestructor;
  18. fn_ptr data_ptr;
  19. size_t data_size;
  20. template<typename func>
  21. static ret invoke(func* fn, args&&... fw_args) {
  22. return (*fn)(gp::forward<args>(fw_args)...);
  23. }
  24. template<typename func>
  25. static void condestruct(func* dest, func* src) {
  26. if(dest != nullptr) {
  27. new (dest) func(*src);
  28. } else {
  29. src->~func();
  30. }
  31. }
  32. static void nop_condestruct(char*, char*) {
  33. return;
  34. }
  35. public:
  36. #pragma clang diagnostic push
  37. #pragma clang diagnostic ignored "-Wnull-dereference"
  38. #pragma gcc diagnostic push
  39. #pragma gcc diagnostic ignored "-Wnull-dereference"
  40. function(allocator& alloc_v)
  41. #pragma gcc pop
  42. #pragma clang diagnostic pop
  43. : alloc(alloc_v)
  44. , invokator(nullptr)
  45. , condestructor(nullptr)
  46. , data_ptr(nullptr)
  47. , data_size(0)
  48. {}
  49. template<typename func>
  50. function(func f, allocator& alloc_v)
  51. : alloc(alloc_v)
  52. , invokator(reinterpret_cast<invoke_fn_t>(invoke<func>))
  53. , condestructor(reinterpret_cast<condestruct_fn_t>(condestruct<func>))
  54. , data_ptr((char*)(alloc.get().allocate(sizeof(func))))
  55. , data_size(sizeof(func))
  56. {
  57. gp_config::assertion(data_ptr != nullptr, "allocator failed in function");
  58. if(data_ptr != nullptr) this->condestructor(data_ptr, reinterpret_cast<char*>(&f));
  59. }
  60. function(function const& rhs)
  61. : alloc(rhs.alloc)
  62. , invokator(rhs.invokator)
  63. , condestructor(rhs.condestructor)
  64. , data_ptr(rhs.data_size != 0 ? (char*)(alloc.get().allocate(rhs.data_size)) : nullptr)
  65. , data_size(rhs.data_size)
  66. {
  67. gp_config::assertion(data_ptr != nullptr, "allocator failed in function");
  68. if(
  69. data_ptr != nullptr
  70. and rhs.data_ptr != nullptr
  71. ) this->condestructor(data_ptr, rhs.data_ptr);
  72. }
  73. function(function&& rhs)
  74. : alloc(rhs.alloc)
  75. , invokator(rhs.invokator)
  76. , condestructor(rhs.condestructor)
  77. , data_ptr(rhs.data_ptr)
  78. , data_size(rhs.data_size)
  79. {
  80. rhs.data_ptr = nullptr;
  81. }
  82. constexpr function(ret(*fn)(args...), allocator alloc_v)
  83. : alloc(alloc_v)
  84. , invokator(reinterpret_cast<invoke_fn_t>(invoke<ret(args...)>))
  85. , condestructor(nop_condestruct)
  86. , data_ptr(reinterpret_cast<char*>(fn))
  87. , data_size(0)
  88. {}
  89. ~function(){
  90. if(data_size == 0) {
  91. return;
  92. }
  93. if(data_ptr != nullptr) {
  94. condestructor(nullptr, data_ptr);
  95. alloc.get().deallocate(data_ptr);
  96. data_ptr = nullptr;
  97. }
  98. }
  99. function& operator=(function&& rhs) {
  100. gp::swap(alloc, rhs.alloc);
  101. gp::swap(invokator, rhs.invokator);
  102. gp::swap(condestructor, rhs.condestructor);
  103. gp::swap(data_ptr,rhs.data_ptr);
  104. gp::swap(data_size,rhs.data_size);
  105. return *this;
  106. }
  107. ret operator()(args&&... argv) {
  108. return invokator(data_ptr, gp::forward<args>(argv)...);
  109. }
  110. };
  111. /*template <typename ret, typename ...args>
  112. class function<ret(args...)>{
  113. struct virtual_callable
  114. {
  115. virtual void inplace_move(char*) = 0;
  116. virtual virtual_callable* all_copy() = 0;
  117. virtual void inplace_copy(char*) = 0;
  118. virtual virtual_callable* all_move() = 0;
  119. virtual ~virtual_callable() = default;
  120. virtual ret operator() (args...) = 0;
  121. };
  122. template<typename fn>
  123. class callable final : public virtual_callable{
  124. typename gp::remove_reference<fn>::type internal_representation;
  125. public:
  126. callable(const fn func)
  127. : internal_representation{gp::move(func)}
  128. {}
  129. callable(callable&) = default;
  130. callable(callable&&) = default;
  131. virtual ~callable() override = default;
  132. virtual void inplace_copy(char* ptr) override {
  133. new(ptr) callable(*this);
  134. }
  135. virtual virtual_callable* all_copy() override {
  136. return new callable(*this);
  137. }
  138. virtual void inplace_move(char* ptr) override {
  139. new(ptr) callable(gp::move(*this));
  140. }
  141. virtual virtual_callable* all_move() override {
  142. return new callable(gp::move(*this));
  143. }
  144. ret operator() (args... arg_list) override
  145. {
  146. return internal_representation(arg_list...);
  147. }
  148. };
  149. // tweak a way to store a size in there for trivial copy
  150. enum state_t : uint8_t{
  151. INACTIVE = 0,
  152. ACTIVE = 1,
  153. NO_SOO = 0,
  154. SOO = 2
  155. };
  156. state_t state{};
  157. union{
  158. virtual_callable* functor = nullptr;
  159. char inplace[16];
  160. } self;
  161. public:
  162. template <typename T>
  163. function& operator=(T& t)
  164. {
  165. if(state & ACTIVE)
  166. {
  167. if(state & SOO)
  168. {
  169. ((virtual_callable*)self.inplace)->~virtual_callable();
  170. }
  171. else
  172. {
  173. delete self.functor;
  174. }
  175. }
  176. if(!(t.state & ACTIVE))
  177. {
  178. state = INACTIVE;
  179. return;
  180. }
  181. if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
  182. if constexpr (sizeof(callable<T>) <= sizeof(self))
  183. {
  184. new((void*)self.inplace) callable<T>(t);
  185. state = (state_t)(ACTIVE | SOO);
  186. }
  187. else
  188. {
  189. self.functor = new callable<T>(t);
  190. state = (state_t)(ACTIVE | NO_SOO);
  191. }
  192. } else {
  193. if(t.state & SOO)
  194. {
  195. auto& ref = t.self.functor;
  196. ref->inplace_copy((char*)&self);
  197. state = (state_t)(ACTIVE | SOO);
  198. }
  199. else
  200. {
  201. self.functor = t.self.functor->all_copy();
  202. state = (state_t)(ACTIVE | NO_SOO);
  203. }
  204. }
  205. }
  206. function()
  207. {
  208. state = INACTIVE;
  209. }
  210. template<typename T>
  211. function<>(T& t)
  212. {
  213. if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
  214. if constexpr (sizeof(callable<T>) <= sizeof(self))
  215. {
  216. new((void*)self.inplace) callable<T>(t);
  217. state = (state_t)(ACTIVE | SOO);
  218. }
  219. else
  220. {
  221. self.functor = new callable<T>(t);
  222. state = (state_t)(ACTIVE | NO_SOO);
  223. }
  224. } else {
  225. if(t.state & SOO)
  226. {
  227. t.self.functor->inplace_copy(self.inplace);
  228. state = (state_t)(ACTIVE | SOO);
  229. }
  230. else
  231. {
  232. self.functor = t.self.functor->all_copy();
  233. state = (state_t)(ACTIVE | NO_SOO);
  234. }
  235. }
  236. }
  237. template <typename T>
  238. function(T&& t)
  239. {
  240. if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
  241. if constexpr (sizeof(callable<T>) <= sizeof(self))
  242. {
  243. new((void*)self.inplace) callable<T>(gp::move(t));
  244. state = (state_t)(ACTIVE | SOO);
  245. }
  246. else
  247. {
  248. self.functor = new callable<T>(gp::move(t));
  249. state = (state_t)(ACTIVE | NO_SOO);
  250. }
  251. } else {
  252. if(t.state & SOO)
  253. {
  254. auto& ref = t.self.functor;
  255. ref->inplace_move((char*)&self);
  256. state = (state_t)(ACTIVE | SOO);
  257. }
  258. else
  259. {
  260. self.functor = t.self.functor->all_move();
  261. state = (state_t)(ACTIVE | NO_SOO);
  262. }
  263. }
  264. }
  265. ret operator()(args... arg_list) const {
  266. if constexpr (gp_config::has_exceptions)
  267. {
  268. if(!(state & ACTIVE))
  269. {
  270. throw bad_functor{};
  271. }
  272. }
  273. if(state & SOO)
  274. {
  275. return (*(virtual_callable*)&self)(arg_list...);
  276. }
  277. else
  278. {
  279. return (*self.functor)(arg_list...);
  280. }
  281. }
  282. ~function()
  283. {
  284. if(state & ACTIVE)
  285. {
  286. if(state & SOO)
  287. {
  288. ((virtual_callable*)&self)->~virtual_callable();
  289. }
  290. else
  291. {
  292. delete self.functor;
  293. }
  294. }
  295. }
  296. };*/
  297. }