1 // Copyright 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #pragma once
16
17 #include "base/TypeTraits.h"
18 #include "host-common/logging.h"
19
20 #include <cassert>
21 #include <initializer_list>
22 #include <type_traits>
23 #include <utility>
24
25 #include <cstddef>
26
27 // Optional<T> - a template class to store an optional value of type T.
28 //
29 // Usage examples:
30 //
31 // Initialization and construction:
32 // Optional<Foo> foo; // |foo| doesn't contain a value.
33 // Optional<Foo> foo(Foo(10)); // |foo| contains a copy-constructed value.
34 // Optional<Foo> foo2(foo); // |foo2| contains a copy of |foo|'s value.
35 // Optional<Foo> foo3(std::move(foo2)); // Guess what?
36 //
37 // Assignment:
38 // Foo foo_value(0);
39 // Optional<Foo> foo; // |foo| is empty.
40 // Optional<Foo> foo2; // |foo2| is empty.
41 // foo2 = foo; // |foo2| is still empty.
42 // foo = foo_value; // set value of |foo| to a copy of |foo_value|
43 // foo = std::move(foo_value); // move |foo_value| into |foo|.
44 // foo2 = foo; // now |foo2| has a copy of |foo|'s value.
45 // foo = kNullopt; // unset |foo|, it has no value.
46 //
47 // Checking and accessing value:
48 // if (foo) {
49 // // |foo| has a value.
50 // doStuff(*foo); // |*foo| is the value inside |foo|.
51 // foo->callMethod(); // Same as (*foo).callMethod().
52 // } else {
53 // // |foo| is empty.
54 // }
55 //
56 // foo.value() // Same as *foo
57 // foo.valueOr(<default>) // Return <default> is |foo| has no value.
58 //
59 // In-place construction:
60 //
61 // Optional<Foo> foo; // |foo| is empty.
62 // foo.emplace(20); // |foo| now contains a value constructed as Foo(20)
63 //
64 // Optional<Foo> foo(kInplace, 20); // |foo| is initialized with a value
65 // // that is constructed in-place as
66 // // Foo(20).
67 //
68 // return makeOptional<Foo>(20); // Takes Foo constructor arguments
69 // // directly.
70 //
71 // Returning values:
72 //
73 // Optional<Foo> myFunc(...) {
74 // if (someCondition) {
75 // return Foo(10); // call Optional<Foo>(Foo&) constructor.
76 // } else {
77 // return {}; // call Optional<Foo>() constructor, which
78 // // builds an empty value.
79 // }
80 // }
81 //
82 // Memory layout:
83 // Optional<Foo> is equivalent to:
84 //
85 // struct {
86 // bool flag;
87 // Foo value;
88 // };
89 //
90 // in terms of memory layout. This means it *doubles* the size of integral
91 // types. Also:
92 //
93 // - Optional<Foo> can be constructed from anything that constructs a Foo.
94 //
95 // - Same with Optional<Foo>(kInplace, Args...) where Args... matches any
96 // arguments that can be passed to a Foo constructor.
97 //
98 // - Comparison operators are provided. Beware: an empty Optional<Foo>
99 // is always smaller than any Foo value.
100
101 namespace android {
102 namespace base {
103
104 namespace details {
105
106 // Base classes to reduce the number of instantiations of the Optional's
107 // internal members.
108 class OptionalFlagBase {
109 public:
setConstructed(bool constructed)110 void setConstructed(bool constructed) { mConstructed = constructed; }
constructed()111 constexpr bool constructed() const { return mConstructed; }
112 constexpr operator bool() const { return constructed(); }
hasValue()113 bool hasValue() const { return constructed(); }
114
115 constexpr OptionalFlagBase(bool constructed = false)
mConstructed(constructed)116 : mConstructed(constructed) {}
117
118 private:
119 bool mConstructed = false;
120 };
121
122 template <size_t Size, size_t Align>
123 class OptionalStorageBase {
124 protected:
125 using StoreT = typename std::aligned_storage<Size, Align>::type;
126 StoreT mStorage = {};
127 };
128
129 } // namespace details
130
131 // A tag type for empty optional construction
132 struct NulloptT {
NulloptTNulloptT133 constexpr explicit NulloptT(int) {}
134 };
135
136 // A tag type for inplace value construction
137 struct InplaceT {
InplaceTInplaceT138 constexpr explicit InplaceT(int) {}
139 };
140
141 // Tag values for null optional and inplace construction
142 constexpr NulloptT kNullopt{1};
143 constexpr InplaceT kInplace{1};
144
145 // Forward declaration for an early use
146 template <class T>
147 class Optional;
148
149 // A type trait for checking if a type is an optional instantiation
150 // Note: if you want to refer to the template name inside the template,
151 // you need to declare this alias outside of it - because the
152 // class name inside of the template stands for an instantiated template
153 // E.g, for template <T> class Foo if you say 'Foo' inside the class, it
154 // actually means Foo<T>;
155 template <class U>
156 using is_any_optional =
157 is_template_instantiation_of<typename std::decay<U>::type, Optional>;
158
159 template <class T>
160 class Optional
161 : private details::OptionalFlagBase,
162 private details::OptionalStorageBase<sizeof(T),
163 std::alignment_of<T>::value> {
164 // make sure all optionals are buddies - this is needed to implement
165 // conversion from optionals of other types
166 template <class U>
167 friend class Optional;
168
169 template <class U>
170 using self = Optional<U>;
171
172 using base_flag = details::OptionalFlagBase;
173 using base_storage =
174 details::OptionalStorageBase<sizeof(T),
175 std::alignment_of<T>::value>;
176
177 public:
178 // std::optional will have this, so let's provide it
179 using value_type = T;
180
181 // make sure we forbid some Optional instantiations where things may get
182 // really messy
183 static_assert(!std::is_same<typename std::decay<T>::type, NulloptT>::value,
184 "Optional of NulloptT is not allowed");
185 static_assert(!std::is_same<typename std::decay<T>::type, InplaceT>::value,
186 "Optional of InplaceT is not allowed");
187 static_assert(!std::is_reference<T>::value,
188 "Optional references are not allowed: use a pointer instead");
189
190 // constructors
Optional()191 constexpr Optional() {}
Optional(NulloptT)192 constexpr Optional(NulloptT) {}
193
Optional(const Optional & other)194 Optional(const Optional& other) : base_flag(other.constructed()) {
195 if (this->constructed()) {
196 new (&get()) T(other.get());
197 }
198 }
Optional(Optional && other)199 Optional(Optional&& other) : base_flag(other.constructed()) {
200 if (this->constructed()) {
201 new (&get()) T(std::move(other.get()));
202 }
203 }
204
205 // Conversion constructor from optional of similar type
206 template <class U,
207 class = enable_if_c<!is_any_optional<U>::value &&
208 std::is_constructible<T, U>::value>>
Optional(const Optional<U> & other)209 Optional(const Optional<U>& other) : base_flag(other.constructed()) {
210 if (this->constructed()) {
211 new (&get()) T(other.get());
212 }
213 }
214
215 // Move-conversion constructor
216 template <class U,
217 class = enable_if_c<!is_any_optional<U>::value &&
218 std::is_constructible<T, U>::value>>
Optional(Optional<U> && other)219 Optional(Optional<U>&& other) : base_flag(other.constructed()) {
220 if (this->constructed()) {
221 new (&get()) T(std::move(other.get()));
222 }
223 }
224
225 // Construction from a raw value
Optional(const T & value)226 Optional(const T& value) : base_flag(true) { new (&get()) T(value); }
227 // Move construction from a raw value
Optional(T && value)228 Optional(T&& value) : base_flag(true) { new (&get()) T(std::move(value)); }
229
230 // Inplace construction from a list of |T|'s ctor arguments
231 template <class... Args>
Optional(InplaceT,Args &&...args)232 Optional(InplaceT, Args&&... args) : base_flag(true) {
233 new (&get()) T(std::forward<Args>(args)...);
234 }
235
236 // Inplace construction from an initializer list passed into |T|'s ctor
237 template <class U,
238 class = enable_if<
239 std::is_constructible<T, std::initializer_list<U>>>>
Optional(InplaceT,std::initializer_list<U> il)240 Optional(InplaceT, std::initializer_list<U> il) : base_flag(true) {
241 new (&get()) T(il);
242 }
243
244 // direct assignment
245 Optional& operator=(const Optional& other) {
246 if (&other == this) {
247 return *this;
248 }
249
250 if (this->constructed()) {
251 if (other.constructed()) {
252 get() = other.get();
253 } else {
254 destruct();
255 this->setConstructed(false);
256 }
257 } else {
258 if (other.constructed()) {
259 new (&get()) T(other.get());
260 this->setConstructed(true);
261 } else {
262 ; // we're good
263 }
264 }
265 return *this;
266 }
267
268 // move assignment
269 Optional& operator=(Optional&& other) {
270 if (this->constructed()) {
271 if (other.constructed()) {
272 get() = std::move(other.get());
273 } else {
274 destruct();
275 this->setConstructed(false);
276 }
277 } else {
278 if (other.constructed()) {
279 new (&get()) T(std::move(other.get()));
280 this->setConstructed(true);
281 } else {
282 ; // we're good
283 }
284 }
285 return *this;
286 }
287
288 // conversion assignment
289 template <class U,
290 class = enable_if_convertible<typename std::decay<U>::type, T>>
291 Optional& operator=(const Optional<U>& other) {
292 if (this->constructed()) {
293 if (other.constructed()) {
294 get() = other.get();
295 } else {
296 destruct();
297 this->setConstructed(false);
298 }
299 } else {
300 if (other.constructed()) {
301 new (&get()) T(other.get());
302 this->setConstructed(true);
303 } else {
304 ; // we're good
305 }
306 }
307 return *this;
308 }
309
310 // conversion move assignment
311 template <class U,
312 class = enable_if_convertible<typename std::decay<U>::type, T>>
313 Optional& operator=(Optional<U>&& other) {
314 if (this->constructed()) {
315 if (other.constructed()) {
316 get() = std::move(other.get());
317 } else {
318 destruct();
319 this->setConstructed(false);
320 }
321 } else {
322 if (other.constructed()) {
323 new (&get()) T(std::move(other.get()));
324 this->setConstructed(true);
325 } else {
326 ; // we're good
327 }
328 }
329 return *this;
330 }
331
332 // the most complicated one: forwarding constructor for anything convertible
333 // to |T|, excluding the stuff implemented above explicitly
334 template <class U,
335 class = enable_if_c<
336 !is_any_optional<typename std::decay<U>::type>::value &&
337 std::is_convertible<typename std::decay<U>::type,
338 T>::value>>
339 Optional& operator=(U&& other) {
340 if (this->constructed()) {
341 get() = std::forward<U>(other);
342 } else {
343 new (&get()) T(std::forward<U>(other));
344 this->setConstructed(true);
345 }
346 return *this;
347 }
348
349 // Adopt value checkers from the parent
350 using base_flag::operator bool;
351 using base_flag::hasValue;
352
value()353 T& value() {
354 if (!constructed()) {
355 ERR("Optional not constructed");
356 abort();
357 }
358 return get();
359 }
value()360 constexpr const T& value() const {
361 if (!constructed()) {
362 ERR("Optional not constructed");
363 abort();
364 }
365 return get();
366 }
367
ptr()368 T* ptr() {
369 return this->constructed() ? &get() : nullptr;
370 }
ptr()371 constexpr const T* ptr() const {
372 return this->constructed() ? &get() : nullptr;
373 }
374
375 // Value getter with fallback
376 template <class U = T,
377 class = enable_if_convertible<typename std::decay<U>::type, T>>
valueOr(U && defaultValue)378 constexpr T valueOr(U&& defaultValue) const {
379 return this->constructed() ? get() : std::move(defaultValue);
380 }
381
382 // Pointer-like operators
383 T& operator*() {
384 if (!constructed()) {
385 ERR("Optional not constructed");
386 abort();
387 }
388 return get();
389 }
390 constexpr const T& operator*() const {
391 if (!constructed()) {
392 ERR("Optional not constructed");
393 abort();
394 }
395 return get();
396 }
397
398 T* operator->() {
399 if (!constructed()) {
400 ERR("Optional not constructed");
401 abort();
402 }
403 return &get();
404 }
405 constexpr const T* operator->() const {
406 if (!constructed()) {
407 ERR("Optional not constructed");
408 abort();
409 }
410 return &get();
411 }
412
~Optional()413 ~Optional() {
414 if (this->constructed()) {
415 destruct();
416 }
417 }
418
clear()419 void clear() {
420 if (this->constructed()) {
421 destruct();
422 this->setConstructed(false);
423 }
424 }
425
426 template <class U,
427 class = enable_if_convertible<typename std::decay<U>::type, T>>
reset(U && u)428 void reset(U&& u) {
429 *this = std::forward<U>(u);
430 }
431
432 // In-place construction with possible destruction of the old value
433 template <class... Args>
emplace(Args &&...args)434 void emplace(Args&&... args) {
435 if (this->constructed()) {
436 destruct();
437 }
438 new (&get()) T(std::forward<Args>(args)...);
439 this->setConstructed(true);
440 }
441
442 // In-place construction with possible destruction of the old value
443 // initializer-list version
444 template <class U,
445 class = enable_if<
446 std::is_constructible<T, std::initializer_list<U>>>>
emplace(std::initializer_list<U> il)447 void emplace(std::initializer_list<U> il) {
448 if (this->constructed()) {
449 destruct();
450 }
451 new (&get()) T(il);
452 this->setConstructed(true);
453 }
454
455 private:
456 // A helper function to convert the internal raw storage to T&
get()457 constexpr const T& get() const {
458 return *reinterpret_cast<const T*>(
459 reinterpret_cast<const char*>(&this->mStorage));
460 }
461
462 // Same thing, mutable
get()463 T& get() {
464 return const_cast<T&>(const_cast<const Optional*>(this)->get());
465 }
466
467 // Shortcut for a destructor call for the stored object
destruct()468 void destruct() { get().T::~T(); }
469 };
470
471 template <class T>
makeOptional(T && t)472 Optional<typename std::decay<T>::type> makeOptional(T&& t) {
473 return Optional<typename std::decay<T>::type>(std::forward<T>(t));
474 }
475
476 template <class T, class... Args>
makeOptional(Args &&...args)477 Optional<typename std::decay<T>::type> makeOptional(Args&&... args) {
478 return Optional<typename std::decay<T>::type>(kInplace,
479 std::forward<Args>(args)...);
480 }
481
482 template <class T>
483 bool operator==(const Optional<T>& l, const Optional<T>& r) {
484 return l.hasValue() ? r.hasValue() && *l == *r : !r.hasValue();
485 }
486 template <class T>
487 bool operator==(const Optional<T>& l, NulloptT) {
488 return !l;
489 }
490 template <class T>
491 bool operator==(NulloptT, const Optional<T>& r) {
492 return !r;
493 }
494 template <class T>
495 bool operator==(const Optional<T>& l, const T& r) {
496 return bool(l) && *l == r;
497 }
498 template <class T>
499 bool operator==(const T& l, const Optional<T>& r) {
500 return bool(r) && l == *r;
501 }
502
503 template <class T>
504 bool operator!=(const Optional<T>& l, const Optional<T>& r) {
505 return !(l == r);
506 }
507 template <class T>
508 bool operator!=(const Optional<T>& l, NulloptT) {
509 return bool(l);
510 }
511 template <class T>
512 bool operator!=(NulloptT, const Optional<T>& r) {
513 return bool(r);
514 }
515 template <class T>
516 bool operator!=(const Optional<T>& l, const T& r) {
517 return !l || !(*l == r);
518 }
519 template <class T>
520 bool operator!=(const T& l, const Optional<T>& r) {
521 return !r || !(l == *r);
522 }
523
524 template <class T>
525 bool operator<(const Optional<T>& l, const Optional<T>& r) {
526 return !r ? false : (!l ? true : *l < *r);
527 }
528 template <class T>
529 bool operator<(const Optional<T>&, NulloptT) {
530 return false;
531 }
532 template <class T>
533 bool operator<(NulloptT, const Optional<T>& r) {
534 return bool(r);
535 }
536 template <class T>
537 bool operator<(const Optional<T>& l, const T& r) {
538 return !l || *l < r;
539 }
540 template <class T>
541 bool operator<(const T& l, const Optional<T>& r) {
542 return bool(r) && l < *r;
543 }
544
545 } // namespace base
546 } // namespace android
547