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