| 38 | // 2. for reference types, we store a pointer to the referenced value |
| 39 | template<typename T, typename = void> |
| 40 | struct OptionalStorage { |
| 41 | private: |
| 42 | bool has_; |
| 43 | alignas(T) unsigned char value_[sizeof(T)]; |
| 44 | |
| 45 | using Type = std::remove_const_t<T>; |
| 46 | |
| 47 | public: |
| 48 | OptionalStorage() = default; |
| 49 | ~OptionalStorage() = default; |
| 50 | |
| 51 | OptionalStorage(const OptionalStorage&) = delete; |
| 52 | OptionalStorage& operator=(const OptionalStorage&) = delete; |
| 53 | |
| 54 | void Init() { has_ = false; } |
| 55 | |
| 56 | T& Value() & { return *reinterpret_cast<T*>(value_); } |
| 57 | |
| 58 | Type&& Value() && { return std::move(*const_cast<Type*>(reinterpret_cast<T*>(value_))); } |
| 59 | |
| 60 | const T& Value() const& { return *reinterpret_cast<const T*>(value_); } |
| 61 | |
| 62 | bool HasValue() const { return has_; } |
| 63 | |
| 64 | void Reset() { |
| 65 | if (has_) { |
| 66 | has_ = false; |
| 67 | Value().~T(); |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | void Destory() { |
| 72 | if (has_) { Value().~T(); } |
| 73 | } |
| 74 | |
| 75 | template<typename... Args, typename U = Type, std::enable_if_t<IsAggregate<U>, int> = 0> |
| 76 | void Construct(Args&&... args) { |
| 77 | new (value_) Type{std::forward<Args>(args)...}; |
| 78 | has_ = true; |
| 79 | } |
| 80 | |
| 81 | template<typename... Args, typename U = Type, std::enable_if_t<!IsAggregate<U>, int> = 0> |
| 82 | void Construct(Args&&... args) { |
| 83 | new (value_) Type(std::forward<Args>(args)...); |
| 84 | has_ = true; |
| 85 | } |
| 86 | |
| 87 | template<typename... Args, typename U = T, std::enable_if_t<!std::is_const<U>::value, int> = 0> |
| 88 | T& Emplace(Args&&... args) { |
| 89 | if (!has_) { |
| 90 | Construct(std::forward<Args>(args)...); |
| 91 | return Value(); |
| 92 | } else { |
| 93 | return Value() = Type(std::forward<Args>(args)...); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | template<typename... Args, typename U = T, std::enable_if_t<std::is_const<U>::value, int> = 0> |