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.

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