• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "util/TypeTraits.h"
21 
22 #include <cassert>
23 #include <type_traits>
24 #include <utility>
25 
26 namespace aapt {
27 
28 /**
29  * Either holds a valid value of type T, or holds Nothing.
30  * The value is stored inline in this structure, so no
31  * heap memory is used when creating a Maybe<T> object.
32  */
33 template <typename T>
34 class Maybe {
35 public:
36     /**
37      * Construct Nothing.
38      */
39     Maybe();
40 
41     ~Maybe();
42 
43     Maybe(const Maybe& rhs);
44 
45     template <typename U>
46     Maybe(const Maybe<U>& rhs);
47 
48     Maybe(Maybe&& rhs);
49 
50     template <typename U>
51     Maybe(Maybe<U>&& rhs);
52 
53     Maybe& operator=(const Maybe& rhs);
54 
55     template <typename U>
56     Maybe& operator=(const Maybe<U>& rhs);
57 
58     Maybe& operator=(Maybe&& rhs);
59 
60     template <typename U>
61     Maybe& operator=(Maybe<U>&& rhs);
62 
63     /**
64      * Construct a Maybe holding a value.
65      */
66     Maybe(const T& value);
67 
68     /**
69      * Construct a Maybe holding a value.
70      */
71     Maybe(T&& value);
72 
73     /**
74      * True if this holds a value, false if
75      * it holds Nothing.
76      */
77     explicit operator bool() const;
78 
79     /**
80      * Gets the value if one exists, or else
81      * panics.
82      */
83     T& value();
84 
85     /**
86      * Gets the value if one exists, or else
87      * panics.
88      */
89     const T& value() const;
90 
91 private:
92     template <typename U>
93     friend class Maybe;
94 
95     template <typename U>
96     Maybe& copy(const Maybe<U>& rhs);
97 
98     template <typename U>
99     Maybe& move(Maybe<U>&& rhs);
100 
101     void destroy();
102 
103     bool mNothing;
104 
105     typename std::aligned_storage<sizeof(T), alignof(T)>::type mStorage;
106 };
107 
108 template <typename T>
Maybe()109 Maybe<T>::Maybe()
110 : mNothing(true) {
111 }
112 
113 template <typename T>
~Maybe()114 Maybe<T>::~Maybe() {
115     if (!mNothing) {
116         destroy();
117     }
118 }
119 
120 template <typename T>
Maybe(const Maybe & rhs)121 Maybe<T>::Maybe(const Maybe& rhs)
122 : mNothing(rhs.mNothing) {
123     if (!rhs.mNothing) {
124         new (&mStorage) T(reinterpret_cast<const T&>(rhs.mStorage));
125     }
126 }
127 
128 template <typename T>
129 template <typename U>
Maybe(const Maybe<U> & rhs)130 Maybe<T>::Maybe(const Maybe<U>& rhs)
131 : mNothing(rhs.mNothing) {
132     if (!rhs.mNothing) {
133         new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
134     }
135 }
136 
137 template <typename T>
Maybe(Maybe && rhs)138 Maybe<T>::Maybe(Maybe&& rhs)
139 : mNothing(rhs.mNothing) {
140     if (!rhs.mNothing) {
141         rhs.mNothing = true;
142 
143         // Move the value from rhs.
144         new (&mStorage) T(std::move(reinterpret_cast<T&>(rhs.mStorage)));
145         rhs.destroy();
146     }
147 }
148 
149 template <typename T>
150 template <typename U>
Maybe(Maybe<U> && rhs)151 Maybe<T>::Maybe(Maybe<U>&& rhs)
152 : mNothing(rhs.mNothing) {
153     if (!rhs.mNothing) {
154         rhs.mNothing = true;
155 
156         // Move the value from rhs.
157         new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
158         rhs.destroy();
159     }
160 }
161 
162 template <typename T>
163 inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) {
164     // Delegate to the actual assignment.
165     return copy(rhs);
166 }
167 
168 template <typename T>
169 template <typename U>
170 inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
171     return copy(rhs);
172 }
173 
174 template <typename T>
175 template <typename U>
copy(const Maybe<U> & rhs)176 Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) {
177     if (mNothing && rhs.mNothing) {
178         // Both are nothing, nothing to do.
179         return *this;
180     } else if  (!mNothing && !rhs.mNothing) {
181         // We both are something, so assign rhs to us.
182         reinterpret_cast<T&>(mStorage) = reinterpret_cast<const U&>(rhs.mStorage);
183     } else if (mNothing) {
184         // We are nothing but rhs is something.
185         mNothing = rhs.mNothing;
186 
187         // Copy the value from rhs.
188         new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
189     } else {
190         // We are something but rhs is nothing, so destroy our value.
191         mNothing = rhs.mNothing;
192         destroy();
193     }
194     return *this;
195 }
196 
197 template <typename T>
198 inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) {
199     // Delegate to the actual assignment.
200     return move(std::forward<Maybe<T>>(rhs));
201 }
202 
203 template <typename T>
204 template <typename U>
205 inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
206     return move(std::forward<Maybe<U>>(rhs));
207 }
208 
209 template <typename T>
210 template <typename U>
move(Maybe<U> && rhs)211 Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) {
212     if (mNothing && rhs.mNothing) {
213         // Both are nothing, nothing to do.
214         return *this;
215     } else if  (!mNothing && !rhs.mNothing) {
216         // We both are something, so move assign rhs to us.
217         rhs.mNothing = true;
218         reinterpret_cast<T&>(mStorage) = std::move(reinterpret_cast<U&>(rhs.mStorage));
219         rhs.destroy();
220     } else if (mNothing) {
221         // We are nothing but rhs is something.
222         mNothing = false;
223         rhs.mNothing = true;
224 
225         // Move the value from rhs.
226         new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
227         rhs.destroy();
228     } else {
229         // We are something but rhs is nothing, so destroy our value.
230         mNothing = true;
231         destroy();
232     }
233     return *this;
234 }
235 
236 template <typename T>
Maybe(const T & value)237 Maybe<T>::Maybe(const T& value)
238 : mNothing(false) {
239     new (&mStorage) T(value);
240 }
241 
242 template <typename T>
Maybe(T && value)243 Maybe<T>::Maybe(T&& value)
244 : mNothing(false) {
245     new (&mStorage) T(std::forward<T>(value));
246 }
247 
248 template <typename T>
249 Maybe<T>::operator bool() const {
250     return !mNothing;
251 }
252 
253 template <typename T>
value()254 T& Maybe<T>::value() {
255     assert(!mNothing && "Maybe<T>::value() called on Nothing");
256     return reinterpret_cast<T&>(mStorage);
257 }
258 
259 template <typename T>
value()260 const T& Maybe<T>::value() const {
261     assert(!mNothing && "Maybe<T>::value() called on Nothing");
262     return reinterpret_cast<const T&>(mStorage);
263 }
264 
265 template <typename T>
destroy()266 void Maybe<T>::destroy() {
267     reinterpret_cast<T&>(mStorage).~T();
268 }
269 
270 template <typename T>
make_value(T && value)271 inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) {
272     return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value));
273 }
274 
275 template <typename T>
make_nothing()276 inline Maybe<T> make_nothing() {
277     return Maybe<T>();
278 }
279 
280 /**
281  * Define the == operator between Maybe<T> and Maybe<U> only if the operator T == U is defined.
282  * That way the compiler will show an error at the callsite when comparing two Maybe<> objects
283  * whose inner types can't be compared.
284  */
285 template <typename T, typename U>
286 typename std::enable_if<
287         has_eq_op<T, U>::value,
288         bool
289 >::type operator==(const Maybe<T>& a, const Maybe<U>& b) {
290     if (a && b) {
291         return a.value() == b.value();
292     } else if (!a && !b) {
293         return true;
294     }
295     return false;
296 }
297 
298 /**
299  * Same as operator== but negated.
300  */
301 template <typename T, typename U>
302 typename std::enable_if<
303         has_eq_op<T, U>::value,
304         bool
305 >::type operator!=(const Maybe<T>& a, const Maybe<U>& b) {
306     return !(a == b);
307 }
308 
309 } // namespace aapt
310 
311 #endif // AAPT_MAYBE_H
312