aloptional.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #ifndef AL_OPTIONAL_H
  2. #define AL_OPTIONAL_H
  3. #include <initializer_list>
  4. #include <type_traits>
  5. #include <utility>
  6. #include "almalloc.h"
  7. namespace al {
  8. #define REQUIRES(...) bool rt_=true, typename std::enable_if<rt_ && (__VA_ARGS__),bool>::type = true
  9. struct nullopt_t { };
  10. struct in_place_t { };
  11. constexpr nullopt_t nullopt{};
  12. constexpr in_place_t in_place{};
  13. template<typename T>
  14. class optional {
  15. bool mHasValue{false};
  16. union {
  17. char mDummy[sizeof(T)]{};
  18. T mValue;
  19. };
  20. template<typename... Args>
  21. void DoConstruct(Args&& ...args)
  22. {
  23. ::new (std::addressof(mValue)) T{std::forward<Args>(args)...};
  24. mHasValue = true;
  25. }
  26. public:
  27. using value_type = T;
  28. optional() noexcept = default;
  29. optional(nullopt_t) noexcept { }
  30. template<REQUIRES(std::is_copy_constructible<T>::value)>
  31. optional(const optional &rhs) { if(rhs) DoConstruct(*rhs); }
  32. template<REQUIRES(std::is_move_constructible<T>::value)>
  33. optional(optional&& rhs) { if(rhs) DoConstruct(std::move(*rhs)); }
  34. template<typename... Args, REQUIRES(std::is_constructible<T, Args...>::value)>
  35. explicit optional(in_place_t, Args&& ...args) : mHasValue{true}
  36. , mValue{std::forward<Args>(args)...}
  37. { }
  38. template<typename U, typename... Args, REQUIRES(std::is_constructible<T, std::initializer_list<U>&, Args...>::value)>
  39. explicit optional(in_place_t, std::initializer_list<U> il, Args&& ...args)
  40. : mHasValue{true}, mValue{il, std::forward<Args>(args)...}
  41. { }
  42. template<typename U=value_type, REQUIRES(std::is_constructible<T, U&&>::value &&
  43. !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
  44. !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
  45. std::is_constructible<U&&, T>::value)>
  46. constexpr explicit optional(U&& value) : mHasValue{true}, mValue{std::forward<U>(value)}
  47. { }
  48. template<typename U=value_type, REQUIRES(std::is_constructible<T, U&&>::value &&
  49. !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
  50. !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
  51. !std::is_constructible<U&&, T>::value)>
  52. constexpr optional(U&& value) : mHasValue{true}, mValue{std::forward<U>(value)}
  53. { }
  54. ~optional() { if(mHasValue) al::destroy_at(std::addressof(mValue)); }
  55. optional& operator=(nullopt_t) noexcept { reset(); return *this; }
  56. template<REQUIRES(std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value)>
  57. optional& operator=(const optional &rhs)
  58. {
  59. if(!rhs)
  60. reset();
  61. else if(*this)
  62. mValue = *rhs;
  63. else
  64. DoConstruct(*rhs);
  65. return *this;
  66. }
  67. template<REQUIRES(std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)>
  68. optional& operator=(optional&& rhs)
  69. {
  70. if(!rhs)
  71. reset();
  72. else if(*this)
  73. mValue = std::move(*rhs);
  74. else
  75. DoConstruct(std::move(*rhs));
  76. return *this;
  77. }
  78. template<typename U=T, REQUIRES(std::is_constructible<T, U>::value &&
  79. std::is_assignable<T&, U>::value &&
  80. !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
  81. (!std::is_same<typename std::decay<U>::type, T>::value ||
  82. !std::is_scalar<U>::value))>
  83. optional& operator=(U&& rhs)
  84. {
  85. if(*this)
  86. mValue = std::forward<U>(rhs);
  87. else
  88. DoConstruct(std::forward<U>(rhs));
  89. return *this;
  90. }
  91. const T* operator->() const { return std::addressof(mValue); }
  92. T* operator->() { return std::addressof(mValue); }
  93. const T& operator*() const& { return mValue; }
  94. T& operator*() & { return mValue; }
  95. const T&& operator*() const&& { return std::move(mValue); }
  96. T&& operator*() && { return std::move(mValue); }
  97. operator bool() const noexcept { return mHasValue; }
  98. bool has_value() const noexcept { return mHasValue; }
  99. T& value() & { return mValue; }
  100. const T& value() const& { return mValue; }
  101. T&& value() && { return std::move(mValue); }
  102. const T&& value() const&& { return std::move(mValue); }
  103. template<typename U>
  104. T value_or(U&& defval) const&
  105. { return bool{*this} ? **this : static_cast<T>(std::forward<U>(defval)); }
  106. template<typename U>
  107. T value_or(U&& defval) &&
  108. { return bool{*this} ? std::move(**this) : static_cast<T>(std::forward<U>(defval)); }
  109. void reset() noexcept
  110. {
  111. if(mHasValue)
  112. al::destroy_at(std::addressof(mValue));
  113. mHasValue = false;
  114. }
  115. };
  116. template<typename T>
  117. inline optional<typename std::decay<T>::type> make_optional(T&& arg)
  118. { return optional<typename std::decay<T>::type>{in_place, std::forward<T>(arg)}; }
  119. template<typename T, typename... Args>
  120. inline optional<T> make_optional(Args&& ...args)
  121. { return optional<T>{in_place, std::forward<Args>(args)...}; }
  122. template<typename T, typename U, typename... Args>
  123. inline optional<T> make_optional(std::initializer_list<U> il, Args&& ...args)
  124. { return optional<T>{in_place, il, std::forward<Args>(args)...}; }
  125. #undef REQUIRES
  126. } // namespace al
  127. #endif /* AL_SPAN_H */