• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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