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.

175 lines
3.1 KiB

4 years ago
4 years ago
4 years ago
  1. #pragma once
  2. #include "gp/exception.hpp"
  3. #include "gp/algorithm/tmp_manip.hpp"
  4. namespace gp{
  5. template <typename>
  6. class function;
  7. template <typename ret, typename ...args>
  8. class function<ret(args...)>{
  9. struct virtual_callable
  10. {
  11. virtual void inplace_copy(char*) = 0;
  12. virtual virtual_callable* all_copy() = 0;
  13. virtual ~virtual_callable() = default;
  14. virtual ret operator() (args...) = 0;
  15. };
  16. template<typename fn>
  17. class callable : public virtual_callable{
  18. fn internal_representation;
  19. public:
  20. callable(const fn& func)
  21. : internal_representation{func}
  22. {}
  23. callable(callable&) = default;
  24. virtual ~callable() override = default;
  25. virtual void inplace_copy(char* ptr) override {
  26. new(ptr) callable(*this);
  27. }
  28. virtual virtual_callable* all_copy() override {
  29. return new callable(*this);
  30. }
  31. ret operator() (args... arg_list) override
  32. {
  33. return internal_representation(arg_list...);
  34. }
  35. };
  36. // tweak a way to store a size in there for trivial copy
  37. enum state_t : uint8_t{
  38. INACTIVE = 0,
  39. ACTIVE = 1,
  40. NO_SOO = 0,
  41. SOO = 2
  42. };
  43. state_t state{};
  44. union{
  45. virtual_callable* functor = nullptr;
  46. char inplace[12];
  47. } self;
  48. public:
  49. template <typename T>
  50. function& operator=(T& t)
  51. {
  52. if(state & ACTIVE)
  53. {
  54. if(state & SOO)
  55. {
  56. ((virtual_callable*)self.inplace)->~virtual_callable();
  57. }
  58. else
  59. {
  60. delete self.functor;
  61. }
  62. }
  63. if(t.state | ACTIVE)
  64. {
  65. if constexpr (sizeof(callable<T>) <= sizeof(self))
  66. {
  67. t.self.functor->inplace_copy(self.inplace);
  68. state = (state_t)(ACTIVE | SOO);
  69. }
  70. else
  71. {
  72. self.functor = t.self.functor->all_copy();
  73. state = (state_t)(ACTIVE | NO_SOO);
  74. }
  75. return;
  76. }
  77. state = INACTIVE;
  78. }
  79. function()
  80. {
  81. state = INACTIVE;
  82. }
  83. template <typename T>
  84. function(T t)
  85. {
  86. if constexpr (sizeof(callable<T>) <= sizeof(self))
  87. {
  88. new((void*)self.inplace) callable<T>(t);
  89. state = (state_t)(ACTIVE | SOO);
  90. }
  91. else
  92. {
  93. self.functor = new callable<T>(t);
  94. state = (state_t)(ACTIVE | NO_SOO);
  95. }
  96. }
  97. template<>
  98. function<function>(function& t) {
  99. if(t.state & SOO)
  100. {
  101. t.self.functor->inplace_copy(self.inplace);
  102. state = (state_t)(ACTIVE | SOO);
  103. }
  104. else
  105. {
  106. self.functor = t.self.functor->all_copy();
  107. state = (state_t)(ACTIVE | NO_SOO);
  108. }
  109. }
  110. template <typename T>
  111. function(T& t)
  112. {
  113. if constexpr (sizeof(callable<T>) <= sizeof(self))
  114. {
  115. new((void*)&self) callable<T>(t);
  116. state = (state_t)(ACTIVE | SOO);
  117. }
  118. else
  119. {
  120. self.functor = new callable<T>(t);
  121. state = (state_t)(ACTIVE | NO_SOO);
  122. }
  123. }
  124. ret operator()(args... arg_list) const {
  125. if constexpr (gp_config::has_exceptions)
  126. {
  127. if(!(state & ACTIVE))
  128. {
  129. throw bad_functor{};
  130. }
  131. }
  132. if(state & SOO)
  133. {
  134. return (*(virtual_callable*)&self)(arg_list...);
  135. }
  136. else
  137. {
  138. return (*self.functor)(arg_list...);
  139. }
  140. }
  141. ~function()
  142. {
  143. if(state & ACTIVE)
  144. {
  145. if(state & SOO)
  146. {
  147. ((virtual_callable*)&self)->~virtual_callable();
  148. }
  149. else
  150. {
  151. delete self.functor;
  152. }
  153. }
  154. }
  155. };
  156. }