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.

227 lines
4.2 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include "gp/algorithm/modifiers.hpp"
  4. #include "gp/algorithm/move.hpp"
  5. #include "gp/exception.hpp"
  6. #include <type_traits>
  7. namespace gp{
  8. struct nullopt_t{};
  9. constexpr nullopt_t nullopt;
  10. template<
  11. typename T,
  12. typename allocator = gp_config::memory_module::default_allocator,
  13. bool copy_allocator = false,
  14. bool B = std::is_final<T>::value || std::is_fundamental<T>::value
  15. >
  16. class optional;
  17. template<typename T, typename allocator, bool copy_allocator>
  18. class optional<T, allocator, copy_allocator, true>{
  19. bool ready = false;
  20. char buffer[sizeof(T)];
  21. typename gp::either<
  22. copy_allocator,
  23. allocator,
  24. gp::reference_wrapper<allocator>
  25. >::type alloc;
  26. public:
  27. constexpr optional(allocator p = allocator{})
  28. : ready{false}
  29. , alloc(p)
  30. {}
  31. constexpr optional(nullopt_t, allocator p = allocator{})
  32. : ready{false}
  33. , alloc(p)
  34. {}
  35. constexpr optional(T& value, allocator p = allocator{})
  36. : ready{true}
  37. , alloc(p)
  38. {
  39. new(buffer) T(value);
  40. }
  41. constexpr optional(T&& value, allocator p = allocator{})
  42. : ready{true}
  43. , alloc(p)
  44. {
  45. new(buffer) T(gp::move(value));
  46. }
  47. optional& operator=(nullopt_t) {
  48. if(ready) {
  49. ((T*)buffer)->~T();
  50. ready = false;
  51. }
  52. return *this;
  53. }
  54. optional& operator=(T& value) {
  55. if(ready) {
  56. *(T*)buffer = value;
  57. } else {
  58. ready = true;
  59. new(buffer) T(value);
  60. }
  61. return *this;
  62. }
  63. optional& operator=(T&& value) {
  64. if(ready) {
  65. *(T*)buffer = gp::move(value);
  66. } else {
  67. ready = true;
  68. new(buffer) T(gp::move(value));
  69. }
  70. return *this;
  71. }
  72. constexpr bool has_value()
  73. {
  74. return ready;
  75. }
  76. constexpr T& value()
  77. {
  78. if constexpr (gp_config::has_exceptions)
  79. {
  80. if(!ready)
  81. {
  82. throw bad_optional{};
  83. }
  84. } else {
  85. gp_config::assertion(ready, "bad optional access");
  86. }
  87. return *reinterpret_cast<T*>(buffer);
  88. }
  89. };
  90. template<typename T, typename allocator, bool copy_allocator>
  91. class optional<T, allocator, copy_allocator, false>{
  92. bool ready = false;
  93. T* ptr;
  94. typename gp::either<
  95. copy_allocator,
  96. allocator,
  97. gp::reference_wrapper<allocator>
  98. >::type alloc;
  99. public:
  100. constexpr optional(allocator p = allocator{})
  101. : ready{false}
  102. , alloc(p)
  103. {}
  104. constexpr optional(nullopt_t, allocator p = allocator{})
  105. : ready{false}
  106. , alloc(p)
  107. {}
  108. template<typename U>
  109. constexpr optional(U& value, allocator p = allocator{})
  110. : ready{true}
  111. , alloc(p)
  112. {
  113. ptr = new U(value); // TODO: Use allocators
  114. }
  115. template<typename U>
  116. constexpr optional(U&& value, allocator p = allocator{})
  117. : ready{true}
  118. , alloc(p)
  119. {
  120. ptr = new U(gp::move(value)); // TODO: Use allocators
  121. }
  122. optional& operator=(nullopt_t) {
  123. if(ready) {
  124. delete ptr;
  125. ready = false;
  126. }
  127. return *this;
  128. }
  129. template<typename U>
  130. optional& operator=(U& value) {
  131. if(ready) {
  132. if constexpr (std::is_same_v<T, U>) {
  133. *ptr = value;
  134. } else {
  135. delete ptr; // TODO: Use allocators
  136. ptr = new U(value); // TODO: Use allocators
  137. }
  138. } else {
  139. ready = true;
  140. ptr = new U(value); // TODO: Use allocators
  141. }
  142. return *this;
  143. }
  144. optional& operator=(optional&& value){
  145. if(ready) {
  146. delete ptr; // TODO: Use allocators
  147. }
  148. if(value.ready) {
  149. ptr = value.ptr;
  150. value.ready = false;
  151. ready = true;
  152. return *this;
  153. } else {
  154. ready = false;
  155. return *this;
  156. }
  157. }
  158. template<typename U>
  159. optional& operator=(U&& value) {
  160. if(ready) {
  161. if constexpr (std::is_same_v<T, U>) {
  162. *ptr = gp::move(value);
  163. } else {
  164. delete ptr; // TODO: Use allocators
  165. ptr = new U(gp::move(value)); // TODO: Use allocators
  166. }
  167. } else {
  168. ready = true;
  169. ptr = new U(gp::move(value)); // TODO: Use allocators
  170. }
  171. return *this;
  172. }
  173. operator T&() {
  174. gp_config::assertion(ready, "bad optional access");
  175. return *ptr;
  176. }
  177. constexpr bool has_value()
  178. {
  179. return ready;
  180. }
  181. constexpr T& value()
  182. {
  183. if constexpr (gp_config::has_exceptions)
  184. {
  185. if(!ready)
  186. {
  187. throw bad_optional{};
  188. }
  189. } else {
  190. gp_config::assertion(ready, "bad optional access");
  191. }
  192. return *ptr;
  193. }
  194. ~optional() {
  195. if(ready) {
  196. delete ptr; // TODO: Use allocators
  197. }
  198. }
  199. };
  200. }