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 <type_traits>
21#include <utility>
22
23#include "android-base/logging.h"
24
25#include "util/TypeTraits.h"
26
27namespace 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 {
36 public:
37  /**
38   * Construct Nothing.
39   */
40  Maybe();
41
42  ~Maybe();
43
44  Maybe(const Maybe& rhs);
45
46  template <typename U>
47  Maybe(const Maybe<U>& rhs);  // NOLINT(implicit)
48
49  Maybe(Maybe&& rhs);
50
51  template <typename U>
52  Maybe(Maybe<U>&& rhs);  // NOLINT(implicit)
53
54  Maybe& operator=(const Maybe& rhs);
55
56  template <typename U>
57  Maybe& operator=(const Maybe<U>& rhs);
58
59  Maybe& operator=(Maybe&& rhs);
60
61  template <typename U>
62  Maybe& operator=(Maybe<U>&& rhs);
63
64  /**
65   * Construct a Maybe holding a value.
66   */
67  Maybe(const T& value);  // NOLINT(implicit)
68
69  /**
70   * Construct a Maybe holding a value.
71   */
72  Maybe(T&& value);  // NOLINT(implicit)
73
74  /**
75   * True if this holds a value, false if
76   * it holds Nothing.
77   */
78  explicit operator bool() const;
79
80  /**
81   * Gets the value if one exists, or else
82   * panics.
83   */
84  T& value();
85
86  /**
87   * Gets the value if one exists, or else
88   * panics.
89   */
90  const T& value() const;
91
92  T value_or_default(const T& def) const;
93
94 private:
95  template <typename U>
96  friend class Maybe;
97
98  template <typename U>
99  Maybe& copy(const Maybe<U>& rhs);
100
101  template <typename U>
102  Maybe& move(Maybe<U>&& rhs);
103
104  void destroy();
105
106  bool nothing_;
107
108  typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
109};
110
111template <typename T>
112Maybe<T>::Maybe() : nothing_(true) {}
113
114template <typename T>
115Maybe<T>::~Maybe() {
116  if (!nothing_) {
117    destroy();
118  }
119}
120
121template <typename T>
122Maybe<T>::Maybe(const Maybe& rhs) : nothing_(rhs.nothing_) {
123  if (!rhs.nothing_) {
124    new (&storage_) T(reinterpret_cast<const T&>(rhs.storage_));
125  }
126}
127
128template <typename T>
129template <typename U>
130Maybe<T>::Maybe(const Maybe<U>& rhs) : nothing_(rhs.nothing_) {
131  if (!rhs.nothing_) {
132    new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_));
133  }
134}
135
136template <typename T>
137Maybe<T>::Maybe(Maybe&& rhs) : nothing_(rhs.nothing_) {
138  if (!rhs.nothing_) {
139    rhs.nothing_ = true;
140
141    // Move the value from rhs.
142    new (&storage_) T(std::move(reinterpret_cast<T&>(rhs.storage_)));
143    rhs.destroy();
144  }
145}
146
147template <typename T>
148template <typename U>
149Maybe<T>::Maybe(Maybe<U>&& rhs) : nothing_(rhs.nothing_) {
150  if (!rhs.nothing_) {
151    rhs.nothing_ = true;
152
153    // Move the value from rhs.
154    new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_)));
155    rhs.destroy();
156  }
157}
158
159template <typename T>
160inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) {
161  // Delegate to the actual assignment.
162  return copy(rhs);
163}
164
165template <typename T>
166template <typename U>
167inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
168  return copy(rhs);
169}
170
171template <typename T>
172template <typename U>
173Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) {
174  if (nothing_ && rhs.nothing_) {
175    // Both are nothing, nothing to do.
176    return *this;
177  } else if (!nothing_ && !rhs.nothing_) {
178    // We both are something, so assign rhs to us.
179    reinterpret_cast<T&>(storage_) = reinterpret_cast<const U&>(rhs.storage_);
180  } else if (nothing_) {
181    // We are nothing but rhs is something.
182    nothing_ = rhs.nothing_;
183
184    // Copy the value from rhs.
185    new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_));
186  } else {
187    // We are something but rhs is nothing, so destroy our value.
188    nothing_ = rhs.nothing_;
189    destroy();
190  }
191  return *this;
192}
193
194template <typename T>
195inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) {
196  // Delegate to the actual assignment.
197  return move(std::forward<Maybe<T>>(rhs));
198}
199
200template <typename T>
201template <typename U>
202inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
203  return move(std::forward<Maybe<U>>(rhs));
204}
205
206template <typename T>
207template <typename U>
208Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) {
209  if (nothing_ && rhs.nothing_) {
210    // Both are nothing, nothing to do.
211    return *this;
212  } else if (!nothing_ && !rhs.nothing_) {
213    // We both are something, so move assign rhs to us.
214    rhs.nothing_ = true;
215    reinterpret_cast<T&>(storage_) =
216        std::move(reinterpret_cast<U&>(rhs.storage_));
217    rhs.destroy();
218  } else if (nothing_) {
219    // We are nothing but rhs is something.
220    nothing_ = false;
221    rhs.nothing_ = true;
222
223    // Move the value from rhs.
224    new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_)));
225    rhs.destroy();
226  } else {
227    // We are something but rhs is nothing, so destroy our value.
228    nothing_ = true;
229    destroy();
230  }
231  return *this;
232}
233
234template <typename T>
235Maybe<T>::Maybe(const T& value) : nothing_(false) {
236  new (&storage_) T(value);
237}
238
239template <typename T>
240Maybe<T>::Maybe(T&& value) : nothing_(false) {
241  new (&storage_) T(std::forward<T>(value));
242}
243
244template <typename T>
245Maybe<T>::operator bool() const {
246  return !nothing_;
247}
248
249template <typename T>
250T& Maybe<T>::value() {
251  CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
252  return reinterpret_cast<T&>(storage_);
253}
254
255template <typename T>
256const T& Maybe<T>::value() const {
257  CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
258  return reinterpret_cast<const T&>(storage_);
259}
260
261template <typename T>
262T Maybe<T>::value_or_default(const T& def) const {
263  if (nothing_) {
264    return def;
265  }
266  return reinterpret_cast<const T&>(storage_);
267}
268
269template <typename T>
270void Maybe<T>::destroy() {
271  reinterpret_cast<T&>(storage_).~T();
272}
273
274template <typename T>
275inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) {
276  return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value));
277}
278
279template <typename T>
280inline Maybe<T> make_nothing() {
281  return Maybe<T>();
282}
283
284// 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.
287template <typename T, typename U>
288typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a,
289                                                                       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
298template <typename T, typename U>
299typename 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) {
308  return !(a == b);
309}
310
311template <typename T, typename U>
312typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(const Maybe<T>& a,
313                                                                      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;
320}
321
322}  // namespace aapt
323
324#endif  // AAPT_MAYBE_H
325