• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 namespace 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  */
34 template <typename T>
35 class 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(google-explicit-constructor)
48 
49   Maybe(Maybe&& rhs) noexcept;
50 
51   template <typename U>
52   Maybe(Maybe<U>&& rhs);  // NOLINT(google-explicit-constructor)
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) noexcept;
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(google-explicit-constructor)
68 
69   /**
70    * Construct a Maybe holding a value.
71    */
72   Maybe(T&& value);  // NOLINT(google-explicit-constructor)
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 
111 template <typename T>
Maybe()112 Maybe<T>::Maybe() : nothing_(true) {}
113 
114 template <typename T>
~Maybe()115 Maybe<T>::~Maybe() {
116   if (!nothing_) {
117     destroy();
118   }
119 }
120 
121 template <typename T>
Maybe(const Maybe & rhs)122 Maybe<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 
128 template <typename T>
129 template <typename U>
Maybe(const Maybe<U> & rhs)130 Maybe<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 
136 template <typename T>
Maybe(Maybe && rhs)137 Maybe<T>::Maybe(Maybe&& rhs) noexcept : 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 
147 template <typename T>
148 template <typename U>
Maybe(Maybe<U> && rhs)149 Maybe<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 
159 template <typename T>
160 inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) {
161   // Delegate to the actual assignment.
162   return copy(rhs);
163 }
164 
165 template <typename T>
166 template <typename U>
167 inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
168   return copy(rhs);
169 }
170 
171 template <typename T>
172 template <typename U>
copy(const Maybe<U> & rhs)173 Maybe<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 
194 template <typename T>
195 inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept {
196   // Delegate to the actual assignment.
197   return move(std::forward<Maybe<T>>(rhs));
198 }
199 
200 template <typename T>
201 template <typename U>
202 inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
203   return move(std::forward<Maybe<U>>(rhs));
204 }
205 
206 template <typename T>
207 template <typename U>
move(Maybe<U> && rhs)208 Maybe<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 
234 template <typename T>
Maybe(const T & value)235 Maybe<T>::Maybe(const T& value) : nothing_(false) {
236   new (&storage_) T(value);
237 }
238 
239 template <typename T>
Maybe(T && value)240 Maybe<T>::Maybe(T&& value) : nothing_(false) {
241   new (&storage_) T(std::forward<T>(value));
242 }
243 
244 template <typename T>
245 Maybe<T>::operator bool() const {
246   return !nothing_;
247 }
248 
249 template <typename T>
value()250 T& Maybe<T>::value() {
251   CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
252   return reinterpret_cast<T&>(storage_);
253 }
254 
255 template <typename T>
value()256 const T& Maybe<T>::value() const {
257   CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
258   return reinterpret_cast<const T&>(storage_);
259 }
260 
261 template <typename T>
value_or_default(const T & def)262 T 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 
269 template <typename T>
destroy()270 void Maybe<T>::destroy() {
271   reinterpret_cast<T&>(storage_).~T();
272 }
273 
274 template <typename T>
make_value(T && value)275 inline 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 
279 template <typename T>
make_nothing()280 inline 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.
287 template <typename T, typename U>
288 typename 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 
298 template <typename T, typename U>
299 typename 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.
305 template <typename T, typename U>
306 typename 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 
311 template <typename T, typename U>
312 typename 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