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.

416 lines
9.4 KiB

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