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