|
27 | 27 |
|
28 | 28 | namespace llvm {
|
29 | 29 |
|
30 |
| -namespace optional_detail { |
31 |
| -/// Storage for any type. |
32 |
| -template <typename T, bool IsPodLike> struct OptionalStorage { |
| 30 | +template<typename T> |
| 31 | +class Optional { |
33 | 32 | AlignedCharArrayUnion<T> storage;
|
34 | 33 | bool hasVal = false;
|
35 | 34 |
|
36 |
| - OptionalStorage() = default; |
| 35 | +public: |
| 36 | + using value_type = T; |
37 | 37 |
|
38 |
| - OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); } |
39 |
| - OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) { |
| 38 | + Optional(NoneType) {} |
| 39 | + explicit Optional() {} |
| 40 | + |
| 41 | + Optional(const T &y) : hasVal(true) { |
| 42 | + new (storage.buffer) T(y); |
| 43 | + } |
| 44 | + |
| 45 | + Optional(const Optional &O) : hasVal(O.hasVal) { |
40 | 46 | if (hasVal)
|
41 |
| - new (storage.buffer) T(*O.getPointer()); |
| 47 | + new (storage.buffer) T(*O); |
42 | 48 | }
|
43 |
| - OptionalStorage(T &&y) : hasVal(true) { |
| 49 | + |
| 50 | + Optional(T &&y) : hasVal(true) { |
44 | 51 | new (storage.buffer) T(std::forward<T>(y));
|
45 | 52 | }
|
46 |
| - OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) { |
47 |
| - if (O.hasVal) { |
48 |
| - new (storage.buffer) T(std::move(*O.getPointer())); |
| 53 | + |
| 54 | + Optional(Optional<T> &&O) : hasVal(O) { |
| 55 | + if (O) { |
| 56 | + new (storage.buffer) T(std::move(*O)); |
49 | 57 | O.reset();
|
50 | 58 | }
|
51 | 59 | }
|
52 | 60 |
|
53 |
| - OptionalStorage &operator=(T &&y) { |
| 61 | + ~Optional() { |
| 62 | + reset(); |
| 63 | + } |
| 64 | + |
| 65 | + Optional &operator=(T &&y) { |
54 | 66 | if (hasVal)
|
55 |
| - *getPointer() = std::move(y); |
| 67 | + **this = std::move(y); |
56 | 68 | else {
|
57 | 69 | new (storage.buffer) T(std::move(y));
|
58 | 70 | hasVal = true;
|
59 | 71 | }
|
60 | 72 | return *this;
|
61 | 73 | }
|
62 |
| - OptionalStorage &operator=(OptionalStorage &&O) { |
63 |
| - if (!O.hasVal) |
| 74 | + |
| 75 | + Optional &operator=(Optional &&O) { |
| 76 | + if (!O) |
64 | 77 | reset();
|
65 | 78 | else {
|
66 |
| - *this = std::move(*O.getPointer()); |
| 79 | + *this = std::move(*O); |
67 | 80 | O.reset();
|
68 | 81 | }
|
69 | 82 | return *this;
|
70 | 83 | }
|
71 | 84 |
|
| 85 | + /// Create a new object by constructing it in place with the given arguments. |
| 86 | + template<typename ...ArgTypes> |
| 87 | + void emplace(ArgTypes &&...Args) { |
| 88 | + reset(); |
| 89 | + hasVal = true; |
| 90 | + new (storage.buffer) T(std::forward<ArgTypes>(Args)...); |
| 91 | + } |
| 92 | + |
| 93 | + static inline Optional create(const T* y) { |
| 94 | + return y ? Optional(*y) : Optional(); |
| 95 | + } |
| 96 | + |
72 | 97 | // FIXME: these assignments (& the equivalent const T&/const Optional& ctors)
|
73 | 98 | // could be made more efficient by passing by value, possibly unifying them
|
74 | 99 | // with the rvalue versions above - but this could place a different set of
|
75 | 100 | // requirements (notably: the existence of a default ctor) when implemented
|
76 | 101 | // in that way. Careful SFINAE to avoid such pitfalls would be required.
|
77 |
| - OptionalStorage &operator=(const T &y) { |
| 102 | + Optional &operator=(const T &y) { |
78 | 103 | if (hasVal)
|
79 |
| - *getPointer() = y; |
| 104 | + **this = y; |
80 | 105 | else {
|
81 | 106 | new (storage.buffer) T(y);
|
82 | 107 | hasVal = true;
|
83 | 108 | }
|
84 | 109 | return *this;
|
85 | 110 | }
|
86 |
| - OptionalStorage &operator=(const OptionalStorage &O) { |
87 |
| - if (!O.hasVal) |
| 111 | + |
| 112 | + Optional &operator=(const Optional &O) { |
| 113 | + if (!O) |
88 | 114 | reset();
|
89 | 115 | else
|
90 |
| - *this = *O.getPointer(); |
| 116 | + *this = *O; |
91 | 117 | return *this;
|
92 | 118 | }
|
93 | 119 |
|
94 |
| - ~OptionalStorage() { reset(); } |
95 |
| - |
96 | 120 | void reset() {
|
97 | 121 | if (hasVal) {
|
98 |
| - (*getPointer()).~T(); |
| 122 | + (**this).~T(); |
99 | 123 | hasVal = false;
|
100 | 124 | }
|
101 | 125 | }
|
102 | 126 |
|
103 |
| - T *getPointer() { |
104 |
| - assert(hasVal); |
105 |
| - return reinterpret_cast<T *>(storage.buffer); |
106 |
| - } |
107 |
| - const T *getPointer() const { |
108 |
| - assert(hasVal); |
109 |
| - return reinterpret_cast<const T *>(storage.buffer); |
110 |
| - } |
111 |
| -}; |
112 |
| - |
113 |
| -/// Storage for trivially copyable types only. |
114 |
| -template <typename T> struct OptionalStorage<T, true> { |
115 |
| - AlignedCharArrayUnion<T> storage; |
116 |
| - bool hasVal = false; |
117 |
| - |
118 |
| - OptionalStorage() = default; |
119 |
| - |
120 |
| - OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); } |
121 |
| - OptionalStorage &operator=(const T &y) { |
122 |
| - new (storage.buffer) T(y); |
123 |
| - hasVal = true; |
124 |
| - return *this; |
125 |
| - } |
126 |
| - |
127 |
| - void reset() { hasVal = false; } |
128 |
| -}; |
129 |
| -} // namespace optional_detail |
130 |
| - |
131 |
| -template <typename T> class Optional { |
132 |
| - optional_detail::OptionalStorage<T, isPodLike<T>::value> Storage; |
133 |
| - |
134 |
| -public: |
135 |
| - using value_type = T; |
136 |
| - |
137 |
| - constexpr Optional() {} |
138 |
| - constexpr Optional(NoneType) {} |
139 |
| - |
140 |
| - Optional(const T &y) : Storage(y) {} |
141 |
| - Optional(const Optional &O) = default; |
142 |
| - |
143 |
| - Optional(T &&y) : Storage(std::forward<T>(y)) {} |
144 |
| - Optional(Optional &&O) = default; |
145 |
| - |
146 |
| - Optional &operator=(T &&y) { |
147 |
| - Storage = std::move(y); |
148 |
| - return *this; |
149 |
| - } |
150 |
| - Optional &operator=(Optional &&O) = default; |
151 |
| - |
152 |
| - /// Create a new object by constructing it in place with the given arguments. |
153 |
| - template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { |
154 |
| - reset(); |
155 |
| - Storage.hasVal = true; |
156 |
| - new (getPointer()) T(std::forward<ArgTypes>(Args)...); |
157 |
| - } |
158 |
| - |
159 |
| - static inline Optional create(const T *y) { |
160 |
| - return y ? Optional(*y) : Optional(); |
161 |
| - } |
162 |
| - |
163 |
| - Optional &operator=(const T &y) { |
164 |
| - Storage = y; |
165 |
| - return *this; |
166 |
| - } |
167 |
| - Optional &operator=(const Optional &O) = default; |
168 |
| - |
169 |
| - void reset() { Storage.reset(); } |
170 |
| - |
171 |
| - const T *getPointer() const { |
172 |
| - assert(Storage.hasVal); |
173 |
| - return reinterpret_cast<const T *>(Storage.storage.buffer); |
174 |
| - } |
175 |
| - T *getPointer() { |
176 |
| - assert(Storage.hasVal); |
177 |
| - return reinterpret_cast<T *>(Storage.storage.buffer); |
178 |
| - } |
179 |
| - const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); } |
180 |
| - T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); } |
| 127 | + const T* getPointer() const { assert(hasVal); return reinterpret_cast<const T*>(storage.buffer); } |
| 128 | + T* getPointer() { assert(hasVal); return reinterpret_cast<T*>(storage.buffer); } |
| 129 | + const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } |
| 130 | + T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } |
181 | 131 |
|
182 |
| - explicit operator bool() const { return Storage.hasVal; } |
183 |
| - bool hasValue() const { return Storage.hasVal; } |
| 132 | + explicit operator bool() const { return hasVal; } |
| 133 | + bool hasValue() const { return hasVal; } |
184 | 134 | const T* operator->() const { return getPointer(); }
|
185 | 135 | T* operator->() { return getPointer(); }
|
186 |
| - const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); } |
187 |
| - T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); } |
| 136 | + const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } |
| 137 | + T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); } |
188 | 138 |
|
189 | 139 | template <typename U>
|
190 | 140 | constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
|
191 | 141 | return hasValue() ? getValue() : std::forward<U>(value);
|
192 | 142 | }
|
193 | 143 |
|
194 | 144 | #if LLVM_HAS_RVALUE_REFERENCE_THIS
|
195 |
| - T &&getValue() && { return std::move(*getPointer()); } |
196 |
| - T &&operator*() && { return std::move(*getPointer()); } |
| 145 | + T&& getValue() && { assert(hasVal); return std::move(*getPointer()); } |
| 146 | + T&& operator*() && { assert(hasVal); return std::move(*getPointer()); } |
197 | 147 |
|
198 | 148 | template <typename U>
|
199 | 149 | T getValueOr(U &&value) && {
|
|
0 commit comments