General Purpose library for Freestanding C++ and POSIX systems
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

409 lines
9.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. #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. ? 0
  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) <= sizeof(data_ptr)
  72. ? 0
  73. : sizeof(func)
  74. )
  75. {
  76. gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function");
  77. if(data_ptr != nullptr) this->condestructor(data_size < sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, reinterpret_cast<char*>(&f));
  78. }
  79. template<typename func>
  80. function(func f, nullopt_t alloc_v = nullopt)
  81. : alloc(alloc_v)
  82. , invokator(reinterpret_cast<invoke_fn_t>(invoke<func>))
  83. , condestructor(reinterpret_cast<condestruct_fn_t>(condestruct<func>))
  84. , data_ptr(
  85. sizeof(func) <= sizeof(data_ptr)
  86. ? 0
  87. : details::ensure(
  88. [&](){return alloc.has_value();},
  89. [&](){return (char*)(alloc.value().get().allocate(sizeof(func)));}
  90. )
  91. )
  92. , data_size(
  93. sizeof(func) <= sizeof(data_ptr)
  94. ? 0
  95. : sizeof(func)
  96. )
  97. {
  98. gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function");
  99. if(data_ptr != nullptr) this->condestructor(data_size < sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, reinterpret_cast<char*>(&f));
  100. }
  101. function(function const& rhs)
  102. : alloc(rhs.alloc)
  103. , invokator(rhs.invokator)
  104. , condestructor(rhs.condestructor)
  105. , data_ptr(
  106. rhs.data_size <= sizeof(data_ptr)
  107. ? 0
  108. : details::ensure(
  109. [&](){return alloc.has_value();},
  110. [&](){return (char*)(alloc.value().get().allocate(rhs.data_size));}
  111. )
  112. )
  113. , data_size(rhs.data_size)
  114. {
  115. gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function");
  116. if(
  117. data_ptr != nullptr
  118. and rhs.data_ptr != nullptr
  119. ) this->condestructor(data_size <= sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, rhs.data_ptr);
  120. }
  121. function(function&& rhs)
  122. : alloc(rhs.alloc)
  123. , invokator(rhs.invokator)
  124. , condestructor(rhs.condestructor)
  125. , data_ptr(data_size <= sizeof(data_ptr) ? 0 : rhs.data_ptr)
  126. , data_size(rhs.data_size)
  127. {
  128. if(data_size <= sizeof(data_ptr) && data_size != 0 && data_ptr != nullptr && alloc.has_value()) {
  129. condestructor((char*)&data_ptr, (char*)&rhs.data_ptr);
  130. condestructor(nullptr, (char*)&rhs.data_ptr);
  131. }
  132. rhs.data_ptr = nullptr;
  133. }
  134. ~function(){
  135. if(data_size == 0) {
  136. return;
  137. }
  138. if(data_size <= 0) {
  139. return;
  140. }
  141. if(data_ptr != nullptr && alloc.has_value()) {
  142. condestructor(nullptr, data_ptr);
  143. alloc.value().get().deallocate(data_ptr);
  144. data_ptr = nullptr;
  145. }
  146. if(data_size < sizeof(data_ptr))
  147. {
  148. condestructor(nullptr, (char*)&data_ptr);
  149. }
  150. }
  151. function& operator=(function&& rhs) {
  152. gp::swap(alloc, rhs.alloc);
  153. gp::swap(invokator, rhs.invokator);
  154. gp::swap(condestructor, rhs.condestructor);
  155. gp::swap(data_ptr,rhs.data_ptr);
  156. gp::swap(data_size,rhs.data_size);
  157. return *this;
  158. }
  159. function& operator=(function& rhs) {
  160. alloc = rhs.alloc;
  161. invokator = rhs.invokator;
  162. condestructor = rhs.condestructor;
  163. condestructor(nullptr, data_ptr);
  164. alloc.value().get().deallocate(data_ptr);
  165. data_ptr = rhs.data_size <= sizeof(data_ptr)
  166. ? 0
  167. : details::ensure(
  168. [&](){return alloc.has_value();},
  169. [&](){return (char*)(alloc.value().get().allocate(rhs.data_size));}
  170. );
  171. data_size = rhs.data_size;
  172. gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function");
  173. if(
  174. data_ptr != nullptr
  175. and rhs.data_ptr != nullptr
  176. ) this->condestructor(data_size <= sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, rhs.data_ptr);
  177. return *this;
  178. }
  179. ret operator()(args&&... argv) {
  180. return invokator(data_ptr, gp::forward<args>(argv)...);
  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. }