General Purpose library for Freestanding C++ and POSIX systems
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

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