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.

157 lines
2.5 KiB

4 years ago
4 years ago
4 years ago
4 years ago
  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include "gp/functional/bind_front.hpp"
  4. #include "gp/functional/monostates.hpp"
  5. #include "gp/algorithms/move.hpp"
  6. #include "gp/exception.hpp"
  7. #include <type_traits>
  8. #include <new>
  9. namespace gp{
  10. template<typename T>
  11. class optional final{
  12. bool ready = false;
  13. alignas(T) char buffer[sizeof(T)];
  14. public:
  15. constexpr optional()
  16. : ready{false}
  17. {}
  18. constexpr optional(nullopt_t)
  19. : ready{false}
  20. {}
  21. constexpr optional(T& value)
  22. : ready{true}
  23. {
  24. new(buffer) T(value);
  25. }
  26. constexpr optional(T&& value)
  27. : ready{true}
  28. {
  29. new(buffer) T(gp::move(value));
  30. }
  31. constexpr optional(const optional& oth)
  32. : ready{oth.ready}
  33. {
  34. if(ready) {
  35. new(buffer) T(oth.value());
  36. }
  37. }
  38. constexpr optional(optional&& oth)
  39. : ready{oth.ready}
  40. {
  41. if(ready) {
  42. new(buffer) T(gp::move(oth.value()));
  43. }
  44. }
  45. ~optional() {
  46. if(ready) {
  47. ((T*)buffer)->~T();
  48. }
  49. }
  50. optional& operator=(nullopt_t) {
  51. if(ready) {
  52. ((T*)buffer)->~T();
  53. ready = false;
  54. }
  55. return *this;
  56. }
  57. optional& operator=(T& value) {
  58. if(ready) {
  59. *(T*)buffer = value;
  60. } else {
  61. ready = true;
  62. new(buffer) T(value);
  63. }
  64. return *this;
  65. }
  66. optional& operator=(T&& value) {
  67. if(ready) {
  68. *(T*)buffer = gp::move(value);
  69. } else {
  70. ready = true;
  71. new(buffer) T(gp::move(value));
  72. }
  73. return *this;
  74. }
  75. optional& operator=(const optional& oth) {
  76. if(oth.ready) {
  77. if(ready) {
  78. *(T*)buffer = oth.value();
  79. } else {
  80. ready = true;
  81. new(buffer) T(oth.value());
  82. }
  83. } else {
  84. if(ready) {
  85. ((T*)buffer)->~T();
  86. ready = false;
  87. }
  88. }
  89. return *this;
  90. }
  91. optional& operator=(optional&& oth) {
  92. if(oth.ready) {
  93. if(ready) {
  94. *(T*)buffer = gp::move(oth.value());
  95. } else {
  96. ready = true;
  97. new(buffer) T(gp::move(oth.value()));
  98. }
  99. } else {
  100. if(ready) {
  101. ((T*)buffer)->~T();
  102. ready = false;
  103. }
  104. }
  105. return *this;
  106. }
  107. constexpr bool has_value() const
  108. {
  109. return ready;
  110. }
  111. constexpr T& value()
  112. {
  113. if constexpr (gp_config::has_exceptions)
  114. {
  115. if(!ready)
  116. {
  117. throw bad_optional{};
  118. }
  119. } else {
  120. gp_config::assertion(ready, "bad optional access");
  121. }
  122. return *reinterpret_cast<T*>(buffer);
  123. }
  124. constexpr const T& value() const
  125. {
  126. if constexpr (gp_config::has_exceptions)
  127. {
  128. if(!ready)
  129. {
  130. throw bad_optional{};
  131. }
  132. } else {
  133. gp_config::assertion(ready, "bad optional access");
  134. }
  135. return *reinterpret_cast<const T*>(buffer);
  136. }
  137. };
  138. }