blob: 90a0198b4e42d1105dfa517923c7dd00b6809a2a [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
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
Adam Lesinski803c7c82016-04-06 16:09:43 -070020#include "util/TypeTraits.h"
21
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080022#include <cassert>
23#include <type_traits>
24#include <utility>
25
26namespace 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 */
33template <typename T>
34class Maybe {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070035 public:
36 /**
37 * Construct Nothing.
38 */
39 Maybe();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080040
Adam Lesinskicacb28f2016-10-19 12:18:14 -070041 ~Maybe();
Adam Lesinski24aad162015-04-24 19:19:30 -070042
Adam Lesinskicacb28f2016-10-19 12:18:14 -070043 Maybe(const Maybe& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080044
Adam Lesinskicacb28f2016-10-19 12:18:14 -070045 template <typename U>
46 Maybe(const Maybe<U>& rhs); // NOLINT(implicit)
Adam Lesinski24aad162015-04-24 19:19:30 -070047
Adam Lesinskicacb28f2016-10-19 12:18:14 -070048 Maybe(Maybe&& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080049
Adam Lesinskicacb28f2016-10-19 12:18:14 -070050 template <typename U>
51 Maybe(Maybe<U>&& rhs); // NOLINT(implicit)
Adam Lesinski24aad162015-04-24 19:19:30 -070052
Adam Lesinskicacb28f2016-10-19 12:18:14 -070053 Maybe& operator=(const Maybe& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080054
Adam Lesinskicacb28f2016-10-19 12:18:14 -070055 template <typename U>
56 Maybe& operator=(const Maybe<U>& rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -070057
Adam Lesinskicacb28f2016-10-19 12:18:14 -070058 Maybe& operator=(Maybe&& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080059
Adam Lesinskicacb28f2016-10-19 12:18:14 -070060 template <typename U>
61 Maybe& operator=(Maybe<U>&& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080062
Adam Lesinskicacb28f2016-10-19 12:18:14 -070063 /**
64 * Construct a Maybe holding a value.
65 */
66 Maybe(const T& value); // NOLINT(implicit)
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080067
Adam Lesinskicacb28f2016-10-19 12:18:14 -070068 /**
69 * Construct a Maybe holding a value.
70 */
71 Maybe(T&& value); // NOLINT(implicit)
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080072
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 /**
74 * True if this holds a value, false if
75 * it holds Nothing.
76 */
77 explicit operator bool() const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080078
Adam Lesinskicacb28f2016-10-19 12:18:14 -070079 /**
80 * Gets the value if one exists, or else
81 * panics.
82 */
83 T& value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080084
Adam Lesinskicacb28f2016-10-19 12:18:14 -070085 /**
86 * Gets the value if one exists, or else
87 * panics.
88 */
89 const T& value() const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080090
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091 T valueOrDefault(const T& def) const;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -070092
Adam Lesinskicacb28f2016-10-19 12:18:14 -070093 private:
94 template <typename U>
95 friend class Maybe;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080096
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097 template <typename U>
98 Maybe& copy(const Maybe<U>& rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -070099
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700100 template <typename U>
101 Maybe& move(Maybe<U>&& rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -0700102
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700103 void destroy();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800104
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700105 bool mNothing;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800106
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700107 typename std::aligned_storage<sizeof(T), alignof(T)>::type mStorage;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800108};
109
110template <typename T>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700111Maybe<T>::Maybe() : mNothing(true) {}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800112
113template <typename T>
114Maybe<T>::~Maybe() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700115 if (!mNothing) {
116 destroy();
117 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800118}
119
120template <typename T>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700121Maybe<T>::Maybe(const Maybe& rhs) : mNothing(rhs.mNothing) {
122 if (!rhs.mNothing) {
123 new (&mStorage) T(reinterpret_cast<const T&>(rhs.mStorage));
124 }
Adam Lesinski24aad162015-04-24 19:19:30 -0700125}
126
127template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800128template <typename U>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700129Maybe<T>::Maybe(const Maybe<U>& rhs) : mNothing(rhs.mNothing) {
130 if (!rhs.mNothing) {
131 new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
132 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800133}
134
135template <typename T>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700136Maybe<T>::Maybe(Maybe&& rhs) : mNothing(rhs.mNothing) {
137 if (!rhs.mNothing) {
138 rhs.mNothing = true;
Adam Lesinski24aad162015-04-24 19:19:30 -0700139
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700140 // Move the value from rhs.
141 new (&mStorage) T(std::move(reinterpret_cast<T&>(rhs.mStorage)));
142 rhs.destroy();
143 }
Adam Lesinski24aad162015-04-24 19:19:30 -0700144}
145
146template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800147template <typename U>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700148Maybe<T>::Maybe(Maybe<U>&& rhs) : mNothing(rhs.mNothing) {
149 if (!rhs.mNothing) {
150 rhs.mNothing = true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800151
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700152 // Move the value from rhs.
153 new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
154 rhs.destroy();
155 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800156}
157
158template <typename T>
Adam Lesinski24aad162015-04-24 19:19:30 -0700159inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160 // Delegate to the actual assignment.
161 return copy(rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -0700162}
163
164template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800165template <typename U>
Adam Lesinski24aad162015-04-24 19:19:30 -0700166inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700167 return copy(rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -0700168}
169
170template <typename T>
171template <typename U>
172Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700173 if (mNothing && rhs.mNothing) {
174 // Both are nothing, nothing to do.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800175 return *this;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700176 } else if (!mNothing && !rhs.mNothing) {
177 // We both are something, so assign rhs to us.
178 reinterpret_cast<T&>(mStorage) = reinterpret_cast<const U&>(rhs.mStorage);
179 } else if (mNothing) {
180 // We are nothing but rhs is something.
181 mNothing = rhs.mNothing;
182
183 // Copy the value from rhs.
184 new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
185 } else {
186 // We are something but rhs is nothing, so destroy our value.
187 mNothing = rhs.mNothing;
188 destroy();
189 }
190 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800191}
192
193template <typename T>
Adam Lesinski24aad162015-04-24 19:19:30 -0700194inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700195 // Delegate to the actual assignment.
196 return move(std::forward<Maybe<T>>(rhs));
Adam Lesinski24aad162015-04-24 19:19:30 -0700197}
198
199template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800200template <typename U>
Adam Lesinski24aad162015-04-24 19:19:30 -0700201inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700202 return move(std::forward<Maybe<U>>(rhs));
Adam Lesinski24aad162015-04-24 19:19:30 -0700203}
204
205template <typename T>
206template <typename U>
207Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700208 if (mNothing && rhs.mNothing) {
209 // Both are nothing, nothing to do.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800210 return *this;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700211 } else if (!mNothing && !rhs.mNothing) {
212 // We both are something, so move assign rhs to us.
213 rhs.mNothing = true;
214 reinterpret_cast<T&>(mStorage) =
215 std::move(reinterpret_cast<U&>(rhs.mStorage));
216 rhs.destroy();
217 } else if (mNothing) {
218 // We are nothing but rhs is something.
219 mNothing = false;
220 rhs.mNothing = true;
221
222 // Move the value from rhs.
223 new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
224 rhs.destroy();
225 } else {
226 // We are something but rhs is nothing, so destroy our value.
227 mNothing = true;
228 destroy();
229 }
230 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800231}
232
233template <typename T>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700234Maybe<T>::Maybe(const T& value) : mNothing(false) {
235 new (&mStorage) T(value);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800236}
237
238template <typename T>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239Maybe<T>::Maybe(T&& value) : mNothing(false) {
240 new (&mStorage) T(std::forward<T>(value));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800241}
242
243template <typename T>
244Maybe<T>::operator bool() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700245 return !mNothing;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800246}
247
248template <typename T>
249T& Maybe<T>::value() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700250 assert(!mNothing && "Maybe<T>::value() called on Nothing");
251 return reinterpret_cast<T&>(mStorage);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800252}
253
254template <typename T>
255const T& Maybe<T>::value() const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700256 assert(!mNothing && "Maybe<T>::value() called on Nothing");
257 return reinterpret_cast<const T&>(mStorage);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800258}
259
260template <typename T>
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700261T Maybe<T>::valueOrDefault(const T& def) const {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700262 if (mNothing) {
263 return def;
264 }
265 return reinterpret_cast<const T&>(mStorage);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700266}
267
268template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800269void Maybe<T>::destroy() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700270 reinterpret_cast<T&>(mStorage).~T();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800271}
272
273template <typename T>
274inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800276}
277
278template <typename T>
279inline Maybe<T> make_nothing() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700280 return Maybe<T>();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800281}
282
Adam Lesinskia5870652015-11-20 15:32:30 -0800283/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700284 * Define the == operator between Maybe<T> and Maybe<U> only if the operator T
285 * == U is defined.
286 * That way the compiler will show an error at the callsite when comparing two
287 * Maybe<> objects
Adam Lesinski803c7c82016-04-06 16:09:43 -0700288 * whose inner types can't be compared.
Adam Lesinskia5870652015-11-20 15:32:30 -0800289 */
290template <typename T, typename U>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700291typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(
292 const Maybe<T>& a, const Maybe<U>& b) {
293 if (a && b) {
294 return a.value() == b.value();
295 } else if (!a && !b) {
296 return true;
297 }
298 return false;
Adam Lesinskia5870652015-11-20 15:32:30 -0800299}
300
301/**
302 * Same as operator== but negated.
303 */
304template <typename T, typename U>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700305typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator!=(
306 const Maybe<T>& a, const Maybe<U>& b) {
307 return !(a == b);
Adam Lesinskia5870652015-11-20 15:32:30 -0800308}
309
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700310template <typename T, typename U>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700311typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(
312 const Maybe<T>& a, const Maybe<U>& b) {
313 if (a && b) {
314 return a.value() < b.value();
315 } else if (!a && !b) {
316 return false;
317 }
318 return !a;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700319}
320
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700321} // namespace aapt
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800322
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700323#endif // AAPT_MAYBE_H