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.

412 lines
9.3 KiB

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