1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef AAPT_MAYBE_H
18 #define AAPT_MAYBE_H
19
20 #include <cassert>
21 #include <type_traits>
22 #include <utility>
23
24 namespace aapt {
25
26 /**
27 * Either holds a valid value of type T, or holds Nothing.
28 * The value is stored inline in this structure, so no
29 * heap memory is used when creating a Maybe<T> object.
30 */
31 template <typename T>
32 class Maybe {
33 public:
34 /**
35 * Construct Nothing.
36 */
37 Maybe();
38
39 ~Maybe();
40
41 Maybe(const Maybe& rhs);
42
43 template <typename U>
44 Maybe(const Maybe<U>& rhs);
45
46 Maybe(Maybe&& rhs);
47
48 template <typename U>
49 Maybe(Maybe<U>&& rhs);
50
51 Maybe& operator=(const Maybe& rhs);
52
53 template <typename U>
54 Maybe& operator=(const Maybe<U>& rhs);
55
56 Maybe& operator=(Maybe&& rhs);
57
58 template <typename U>
59 Maybe& operator=(Maybe<U>&& rhs);
60
61 /**
62 * Construct a Maybe holding a value.
63 */
64 Maybe(const T& value);
65
66 /**
67 * Construct a Maybe holding a value.
68 */
69 Maybe(T&& value);
70
71 /**
72 * True if this holds a value, false if
73 * it holds Nothing.
74 */
75 operator bool() const;
76
77 /**
78 * Gets the value if one exists, or else
79 * panics.
80 */
81 T& value();
82
83 /**
84 * Gets the value if one exists, or else
85 * panics.
86 */
87 const T& value() const;
88
89 private:
90 template <typename U>
91 friend class Maybe;
92
93 template <typename U>
94 Maybe& copy(const Maybe<U>& rhs);
95
96 template <typename U>
97 Maybe& move(Maybe<U>&& rhs);
98
99 void destroy();
100
101 bool mNothing;
102
103 typename std::aligned_storage<sizeof(T), alignof(T)>::type mStorage;
104 };
105
106 template <typename T>
Maybe()107 Maybe<T>::Maybe()
108 : mNothing(true) {
109 }
110
111 template <typename T>
~Maybe()112 Maybe<T>::~Maybe() {
113 if (!mNothing) {
114 destroy();
115 }
116 }
117
118 template <typename T>
Maybe(const Maybe & rhs)119 Maybe<T>::Maybe(const Maybe& rhs)
120 : mNothing(rhs.mNothing) {
121 if (!rhs.mNothing) {
122 new (&mStorage) T(reinterpret_cast<const T&>(rhs.mStorage));
123 }
124 }
125
126 template <typename T>
127 template <typename U>
Maybe(const Maybe<U> & rhs)128 Maybe<T>::Maybe(const Maybe<U>& rhs)
129 : mNothing(rhs.mNothing) {
130 if (!rhs.mNothing) {
131 new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
132 }
133 }
134
135 template <typename T>
Maybe(Maybe && rhs)136 Maybe<T>::Maybe(Maybe&& rhs)
137 : mNothing(rhs.mNothing) {
138 if (!rhs.mNothing) {
139 rhs.mNothing = true;
140
141 // Move the value from rhs.
142 new (&mStorage) T(std::move(reinterpret_cast<T&>(rhs.mStorage)));
143 rhs.destroy();
144 }
145 }
146
147 template <typename T>
148 template <typename U>
Maybe(Maybe<U> && rhs)149 Maybe<T>::Maybe(Maybe<U>&& rhs)
150 : mNothing(rhs.mNothing) {
151 if (!rhs.mNothing) {
152 rhs.mNothing = true;
153
154 // Move the value from rhs.
155 new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
156 rhs.destroy();
157 }
158 }
159
160 template <typename T>
161 inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) {
162 // Delegate to the actual assignment.
163 return copy(rhs);
164 }
165
166 template <typename T>
167 template <typename U>
168 inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
169 return copy(rhs);
170 }
171
172 template <typename T>
173 template <typename U>
copy(const Maybe<U> & rhs)174 Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) {
175 if (mNothing && rhs.mNothing) {
176 // Both are nothing, nothing to do.
177 return *this;
178 } else if (!mNothing && !rhs.mNothing) {
179 // We both are something, so assign rhs to us.
180 reinterpret_cast<T&>(mStorage) = reinterpret_cast<const U&>(rhs.mStorage);
181 } else if (mNothing) {
182 // We are nothing but rhs is something.
183 mNothing = rhs.mNothing;
184
185 // Copy the value from rhs.
186 new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
187 } else {
188 // We are something but rhs is nothing, so destroy our value.
189 mNothing = rhs.mNothing;
190 destroy();
191 }
192 return *this;
193 }
194
195 template <typename T>
196 inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) {
197 // Delegate to the actual assignment.
198 return move(std::forward<Maybe<T>>(rhs));
199 }
200
201 template <typename T>
202 template <typename U>
203 inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
204 return move(std::forward<Maybe<U>>(rhs));
205 }
206
207 template <typename T>
208 template <typename U>
move(Maybe<U> && rhs)209 Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) {
210 if (mNothing && rhs.mNothing) {
211 // Both are nothing, nothing to do.
212 return *this;
213 } else if (!mNothing && !rhs.mNothing) {
214 // We both are something, so move assign rhs to us.
215 rhs.mNothing = true;
216 reinterpret_cast<T&>(mStorage) = std::move(reinterpret_cast<U&>(rhs.mStorage));
217 rhs.destroy();
218 } else if (mNothing) {
219 // We are nothing but rhs is something.
220 mNothing = false;
221 rhs.mNothing = true;
222
223 // Move the value from rhs.
224 new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
225 rhs.destroy();
226 } else {
227 // We are something but rhs is nothing, so destroy our value.
228 mNothing = true;
229 destroy();
230 }
231 return *this;
232 }
233
234 template <typename T>
Maybe(const T & value)235 Maybe<T>::Maybe(const T& value)
236 : mNothing(false) {
237 new (&mStorage) T(value);
238 }
239
240 template <typename T>
Maybe(T && value)241 Maybe<T>::Maybe(T&& value)
242 : mNothing(false) {
243 new (&mStorage) T(std::forward<T>(value));
244 }
245
246 template <typename T>
247 Maybe<T>::operator bool() const {
248 return !mNothing;
249 }
250
251 template <typename T>
value()252 T& Maybe<T>::value() {
253 assert(!mNothing && "Maybe<T>::value() called on Nothing");
254 return reinterpret_cast<T&>(mStorage);
255 }
256
257 template <typename T>
value()258 const T& Maybe<T>::value() const {
259 assert(!mNothing && "Maybe<T>::value() called on Nothing");
260 return reinterpret_cast<const T&>(mStorage);
261 }
262
263 template <typename T>
destroy()264 void Maybe<T>::destroy() {
265 reinterpret_cast<T&>(mStorage).~T();
266 }
267
268 template <typename T>
make_value(T && value)269 inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) {
270 return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value));
271 }
272
273 template <typename T>
make_nothing()274 inline Maybe<T> make_nothing() {
275 return Maybe<T>();
276 }
277
278 } // namespace aapt
279
280 #endif // AAPT_MAYBE_H
281