General Purpose library for Freestanding C++ and POSIX systems
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

215 Zeilen
3.7 KiB

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