1 /*++
2 Copyright (c) 2006 Microsoft Corporation
3 
4 Module Name:
5 
6     optional.h
7 
8 Abstract:
9 
10     Discriminated union of a type T.
11     It defines the notion of initialized/uninitialized objects.
12 
13 Author:
14 
15     Leonardo de Moura (leonardo) 2006-09-29.
16 
17 Revision History:
18 
19 --*/
20 
21 #pragma once
22 
23 template<class T>
24 class optional {
25     T* m_obj = nullptr;
26 
destroy()27     void destroy() {
28         dealloc(m_obj);
29         m_obj = nullptr;
30     }
31 
32 public:
optional()33     optional() {}
34 
optional(const T & val)35     explicit optional(const T & val) {
36         m_obj = alloc(T, val);
37     }
38 
optional(T && val)39     explicit optional(T && val) {
40         m_obj = alloc(T, std::move(val));
41     }
42 
optional(optional<T> && val)43     optional(optional<T> && val) noexcept {
44         std::swap(m_obj, val.m_obj);
45     }
46 
optional(const optional<T> & val)47     optional(const optional<T> & val) {
48         if (val.m_obj) {
49             m_obj = alloc(T, *val);
50         }
51     }
52 
~optional()53     ~optional() {
54         destroy();
55     }
56 
undef()57     static optional const & undef() { static optional u;  return u; }
58 
initialized()59     bool initialized() const { return m_obj; }
60     operator bool() const { return m_obj; }
61     bool operator!() const { return !m_obj; }
62 
get()63     T * get() const {
64         return m_obj;
65     }
66 
set_invalid()67     void set_invalid() {
68         destroy();
69     }
70 
71     T * operator->() {
72         SASSERT(m_obj);
73         return m_obj;
74     }
75 
76     T const * operator->() const {
77         SASSERT(m_obj);
78         return m_obj;
79     }
80 
81     const T & operator*() const {
82         SASSERT(m_obj);
83         return *m_obj;
84     }
85 
86     T & operator*() {
87         SASSERT(m_obj);
88         return *m_obj;
89     }
90 
91     optional & operator=(const T & val) {
92         destroy();
93         m_obj = alloc(T, val);
94         return * this;
95     }
96 
97     optional & operator=(optional && val) {
98         std::swap(m_obj, val.m_obj);
99         return *this;
100     }
101 
102     optional & operator=(const optional & val) {
103         if (&val != this) {
104             destroy();
105             if (val.m_obj) {
106                 m_obj = alloc(T, *val);
107             }
108         }
109         return *this;
110     }
111 };
112 
113 
114 /**
115    \brief Template specialization for pointers. NULL represents uninitialized pointers.
116  */
117 template<typename T>
118 class optional<T*> {
119     T * m_ptr;
120 
121     static optional m_undef;
122 
123 public:
124 
optional()125     optional():m_ptr(nullptr) {}
126 
optional(T * val)127     explicit optional(T * val):m_ptr(val) {}
128 
undef()129     static optional const & undef() { return m_undef; }
130 
initialized()131     bool initialized() const { return m_ptr != 0 ; }
132 
133     operator bool() const { return m_ptr != 0; }
134 
135     bool operator!() const { return m_ptr == nullptr; }
136 
reset()137     void reset() { m_ptr = 0; }
138 
139     optional & operator=(T * val) {
140         m_ptr = val;
141         return *this;
142     }
143 
144     optional & operator=(const optional & val) {
145         m_ptr = val.m_ptr;
146         return *this;
147     }
148 
149     T ** operator->() { return &m_ptr; }
150 
151     T * operator*() const { return m_ptr; }
152 
153     T * & operator*() { return m_ptr; }
154 };
155