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.

109 lines
1.7 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/algorithms/move.hpp"
  5. #include "gp/exception.hpp"
  6. #include <type_traits>
  7. #include <new>
  8. namespace gp{
  9. struct nullopt_t final{};
  10. constexpr nullopt_t nullopt;
  11. template<typename T>
  12. class optional final{
  13. bool ready = false;
  14. alignas(T) char buffer[sizeof(T)];
  15. public:
  16. constexpr optional()
  17. : ready{false}
  18. {}
  19. constexpr optional(nullopt_t)
  20. : ready{false}
  21. {}
  22. constexpr optional(T& value)
  23. : ready{true}
  24. {
  25. new(buffer) T(value);
  26. }
  27. constexpr optional(T&& value)
  28. : ready{true}
  29. {
  30. new(buffer) T(gp::forward<T>(value));
  31. }
  32. ~optional() {
  33. if(ready) {
  34. ((T*)buffer)->~T();
  35. }
  36. }
  37. optional& operator=(nullopt_t) {
  38. if(ready) {
  39. ((T*)buffer)->~T();
  40. ready = false;
  41. }
  42. return *this;
  43. }
  44. optional& operator=(T& value) {
  45. if(ready) {
  46. *(T*)buffer = value;
  47. } else {
  48. ready = true;
  49. new(buffer) T(value);
  50. }
  51. return *this;
  52. }
  53. optional& operator=(T&& value) {
  54. if(ready) {
  55. *(T*)buffer = gp::forward<T>(value);
  56. } else {
  57. ready = true;
  58. new(buffer) T(gp::forward<T>(value));
  59. }
  60. return *this;
  61. }
  62. constexpr bool has_value() const
  63. {
  64. return ready;
  65. }
  66. constexpr T& value()
  67. {
  68. if constexpr (gp_config::has_exceptions)
  69. {
  70. if(!ready)
  71. {
  72. throw bad_optional{};
  73. }
  74. } else {
  75. gp_config::assertion(ready, "bad optional access");
  76. }
  77. return *reinterpret_cast<T*>(buffer);
  78. }
  79. constexpr const T& value() const
  80. {
  81. if constexpr (gp_config::has_exceptions)
  82. {
  83. if(!ready)
  84. {
  85. throw bad_optional{};
  86. }
  87. } else {
  88. gp_config::assertion(ready, "bad optional access");
  89. }
  90. return *reinterpret_cast<const T*>(buffer);
  91. }
  92. };
  93. }