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.

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