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