blob: 031276c8b885058c43731b102c98b5a52cbd4cb8 [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 Lesinski6f6ceb72014-11-14 14:48:12 -080020#include <type_traits>
21#include <utility>
22
Adam Lesinskice5e56e2016-10-21 17:56:45 -070023#include "android-base/logging.h"
24
25#include "util/TypeTraits.h"
26
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080027namespace aapt {
28
29/**
30 * Either holds a valid value of type T, or holds Nothing.
31 * The value is stored inline in this structure, so no
32 * heap memory is used when creating a Maybe<T> object.
33 */
34template <typename T>
35class Maybe {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070036 public:
37 /**
38 * Construct Nothing.
39 */
40 Maybe();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080041
Adam Lesinskicacb28f2016-10-19 12:18:14 -070042 ~Maybe();
Adam Lesinski24aad162015-04-24 19:19:30 -070043
Adam Lesinskicacb28f2016-10-19 12:18:14 -070044 Maybe(const Maybe& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080045
Adam Lesinskicacb28f2016-10-19 12:18:14 -070046 template <typename U>
47 Maybe(const Maybe<U>& rhs); // NOLINT(implicit)
Adam Lesinski24aad162015-04-24 19:19:30 -070048
Chih-Hung Hsiehfc816262018-09-25 12:01:21 -070049 Maybe(Maybe&& rhs) noexcept;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080050
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 template <typename U>
52 Maybe(Maybe<U>&& rhs); // NOLINT(implicit)
Adam Lesinski24aad162015-04-24 19:19:30 -070053
Adam Lesinskicacb28f2016-10-19 12:18:14 -070054 Maybe& operator=(const Maybe& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080055
Adam Lesinskicacb28f2016-10-19 12:18:14 -070056 template <typename U>
57 Maybe& operator=(const Maybe<U>& rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -070058
Chih-Hung Hsiehfc816262018-09-25 12:01:21 -070059 Maybe& operator=(Maybe&& rhs) noexcept;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080060
Adam Lesinskicacb28f2016-10-19 12:18:14 -070061 template <typename U>
62 Maybe& operator=(Maybe<U>&& rhs);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080063
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 /**
65 * Construct a Maybe holding a value.
66 */
67 Maybe(const T& value); // NOLINT(implicit)
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080068
Adam Lesinskicacb28f2016-10-19 12:18:14 -070069 /**
70 * Construct a Maybe holding a value.
71 */
72 Maybe(T&& value); // NOLINT(implicit)
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080073
Adam Lesinskicacb28f2016-10-19 12:18:14 -070074 /**
75 * True if this holds a value, false if
76 * it holds Nothing.
77 */
78 explicit operator bool() const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080079
Adam Lesinskicacb28f2016-10-19 12:18:14 -070080 /**
81 * Gets the value if one exists, or else
82 * panics.
83 */
84 T& value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080085
Adam Lesinskicacb28f2016-10-19 12:18:14 -070086 /**
87 * Gets the value if one exists, or else
88 * panics.
89 */
90 const T& value() const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080091
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 T value_or_default(const T& def) const;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -070093
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094 private:
95 template <typename U>
96 friend class Maybe;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080097
Adam Lesinskicacb28f2016-10-19 12:18:14 -070098 template <typename U>
99 Maybe& copy(const Maybe<U>& rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -0700100
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700101 template <typename U>
102 Maybe& move(Maybe<U>&& rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -0700103
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700104 void destroy();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800105
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700106 bool nothing_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800107
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700108 typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800109};
110
111template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700112Maybe<T>::Maybe() : nothing_(true) {}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800113
114template <typename T>
115Maybe<T>::~Maybe() {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700116 if (!nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700117 destroy();
118 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800119}
120
121template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122Maybe<T>::Maybe(const Maybe& rhs) : nothing_(rhs.nothing_) {
123 if (!rhs.nothing_) {
124 new (&storage_) T(reinterpret_cast<const T&>(rhs.storage_));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700125 }
Adam Lesinski24aad162015-04-24 19:19:30 -0700126}
127
128template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800129template <typename U>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700130Maybe<T>::Maybe(const Maybe<U>& rhs) : nothing_(rhs.nothing_) {
131 if (!rhs.nothing_) {
132 new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700133 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800134}
135
136template <typename T>
Chih-Hung Hsiehfc816262018-09-25 12:01:21 -0700137Maybe<T>::Maybe(Maybe&& rhs) noexcept : nothing_(rhs.nothing_) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700138 if (!rhs.nothing_) {
139 rhs.nothing_ = true;
Adam Lesinski24aad162015-04-24 19:19:30 -0700140
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700141 // Move the value from rhs.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142 new (&storage_) T(std::move(reinterpret_cast<T&>(rhs.storage_)));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 rhs.destroy();
144 }
Adam Lesinski24aad162015-04-24 19:19:30 -0700145}
146
147template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800148template <typename U>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149Maybe<T>::Maybe(Maybe<U>&& rhs) : nothing_(rhs.nothing_) {
150 if (!rhs.nothing_) {
151 rhs.nothing_ = true;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800152
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700153 // Move the value from rhs.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154 new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_)));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700155 rhs.destroy();
156 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800157}
158
159template <typename T>
Adam Lesinski24aad162015-04-24 19:19:30 -0700160inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700161 // Delegate to the actual assignment.
162 return copy(rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -0700163}
164
165template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800166template <typename U>
Adam Lesinski24aad162015-04-24 19:19:30 -0700167inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700168 return copy(rhs);
Adam Lesinski24aad162015-04-24 19:19:30 -0700169}
170
171template <typename T>
172template <typename U>
173Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 if (nothing_ && rhs.nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700175 // Both are nothing, nothing to do.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800176 return *this;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177 } else if (!nothing_ && !rhs.nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700178 // We both are something, so assign rhs to us.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 reinterpret_cast<T&>(storage_) = reinterpret_cast<const U&>(rhs.storage_);
180 } else if (nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 // We are nothing but rhs is something.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700182 nothing_ = rhs.nothing_;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183
184 // Copy the value from rhs.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700185 new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 } else {
187 // We are something but rhs is nothing, so destroy our value.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700188 nothing_ = rhs.nothing_;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700189 destroy();
190 }
191 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800192}
193
194template <typename T>
Chih-Hung Hsiehfc816262018-09-25 12:01:21 -0700195inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700196 // Delegate to the actual assignment.
197 return move(std::forward<Maybe<T>>(rhs));
Adam Lesinski24aad162015-04-24 19:19:30 -0700198}
199
200template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800201template <typename U>
Adam Lesinski24aad162015-04-24 19:19:30 -0700202inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700203 return move(std::forward<Maybe<U>>(rhs));
Adam Lesinski24aad162015-04-24 19:19:30 -0700204}
205
206template <typename T>
207template <typename U>
208Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700209 if (nothing_ && rhs.nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 // Both are nothing, nothing to do.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800211 return *this;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700212 } else if (!nothing_ && !rhs.nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700213 // We both are something, so move assign rhs to us.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700214 rhs.nothing_ = true;
215 reinterpret_cast<T&>(storage_) =
216 std::move(reinterpret_cast<U&>(rhs.storage_));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 rhs.destroy();
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 } else if (nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 // We are nothing but rhs is something.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 nothing_ = false;
221 rhs.nothing_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222
223 // Move the value from rhs.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_)));
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700225 rhs.destroy();
226 } else {
227 // We are something but rhs is nothing, so destroy our value.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700228 nothing_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700229 destroy();
230 }
231 return *this;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800232}
233
234template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700235Maybe<T>::Maybe(const T& value) : nothing_(false) {
236 new (&storage_) T(value);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800237}
238
239template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240Maybe<T>::Maybe(T&& value) : nothing_(false) {
241 new (&storage_) T(std::forward<T>(value));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800242}
243
244template <typename T>
245Maybe<T>::operator bool() const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700246 return !nothing_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800247}
248
249template <typename T>
250T& Maybe<T>::value() {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700251 CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
252 return reinterpret_cast<T&>(storage_);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800253}
254
255template <typename T>
256const T& Maybe<T>::value() const {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700257 CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
258 return reinterpret_cast<const T&>(storage_);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800259}
260
261template <typename T>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700262T Maybe<T>::value_or_default(const T& def) const {
263 if (nothing_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700264 return def;
265 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700266 return reinterpret_cast<const T&>(storage_);
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700267}
268
269template <typename T>
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800270void Maybe<T>::destroy() {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700271 reinterpret_cast<T&>(storage_).~T();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800272}
273
274template <typename T>
275inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700276 return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800277}
278
279template <typename T>
280inline Maybe<T> make_nothing() {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700281 return Maybe<T>();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800282}
283
Adam Lesinskic8956882017-06-29 17:53:36 -0700284// Define the == operator between Maybe<T> and Maybe<U> only if the operator T == U is defined.
285// That way the compiler will show an error at the callsite when comparing two Maybe<> objects
286// whose inner types can't be compared.
Adam Lesinskia5870652015-11-20 15:32:30 -0800287template <typename T, typename U>
Adam Lesinskic8956882017-06-29 17:53:36 -0700288typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a,
289 const Maybe<U>& b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700290 if (a && b) {
291 return a.value() == b.value();
292 } else if (!a && !b) {
293 return true;
294 }
295 return false;
Adam Lesinskia5870652015-11-20 15:32:30 -0800296}
297
Adam Lesinskia5870652015-11-20 15:32:30 -0800298template <typename T, typename U>
Adam Lesinskic8956882017-06-29 17:53:36 -0700299typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a,
300 const U& b) {
301 return a ? a.value() == b : false;
302}
303
304// Same as operator== but negated.
305template <typename T, typename U>
306typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator!=(const Maybe<T>& a,
307 const Maybe<U>& b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700308 return !(a == b);
Adam Lesinskia5870652015-11-20 15:32:30 -0800309}
310
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700311template <typename T, typename U>
Adam Lesinskic8956882017-06-29 17:53:36 -0700312typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(const Maybe<T>& a,
313 const Maybe<U>& b) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700314 if (a && b) {
315 return a.value() < b.value();
316 } else if (!a && !b) {
317 return false;
318 }
319 return !a;
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700320}
321
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700322} // namespace aapt
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800323
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700324#endif // AAPT_MAYBE_H