blob: b43f8e87fd68463b2eb1d42ae3eab4b37b890114 [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
Adam Lesinskicacb28f2016-10-19 12:18:14 -070049 Maybe(Maybe&& rhs);
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
Adam Lesinskicacb28f2016-10-19 12:18:14 -070059 Maybe& operator=(Maybe&& rhs);
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>
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700137Maybe<T>::Maybe(Maybe&& rhs) : nothing_(rhs.nothing_) {
138 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>
Adam Lesinski24aad162015-04-24 19:19:30 -0700195inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) {
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 Lesinskia5870652015-11-20 15:32:30 -0800284/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700285 * Define the == operator between Maybe<T> and Maybe<U> only if the operator T
286 * == U is defined.
287 * That way the compiler will show an error at the callsite when comparing two
288 * Maybe<> objects
Adam Lesinski803c7c82016-04-06 16:09:43 -0700289 * whose inner types can't be compared.
Adam Lesinskia5870652015-11-20 15:32:30 -0800290 */
291template <typename T, typename U>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700292typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(
293 const Maybe<T>& a, const Maybe<U>& b) {
294 if (a && b) {
295 return a.value() == b.value();
296 } else if (!a && !b) {
297 return true;
298 }
299 return false;
Adam Lesinskia5870652015-11-20 15:32:30 -0800300}
301
302/**
303 * Same as operator== but negated.
304 */
305template <typename T, typename U>
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700306typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator!=(
307 const Maybe<T>& a, const Maybe<U>& b) {
308 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 Lesinskicacb28f2016-10-19 12:18:14 -0700312typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(
313 const Maybe<T>& a, const Maybe<U>& b) {
314 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