1// Copyright 2019 Google LLC
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// https://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#ifndef dap_optional_h
16#define dap_optional_h
17
18#include <assert.h>
19#include <type_traits>
20#include <utility> // std::move, std::forward
21
22namespace dap {
23
24// optional holds an 'optional' contained value.
25// This is similar to C++17's std::optional.
26template <typename T>
27class optional {
28 template <typename U>
29 using IsConvertibleToT =
30 typename std::enable_if<std::is_convertible<U, T>::value>::type;
31
32 public:
33 using value_type = T;
34
35 // constructors
36 inline optional() = default;
37 inline optional(const optional& other);
38 inline optional(optional&& other);
39 template <typename U>
40 inline optional(const optional<U>& other);
41 template <typename U>
42 inline optional(optional<U>&& other);
43 template <typename U = value_type, typename = IsConvertibleToT<U>>
44 inline optional(U&& value);
45
46 // value() returns the contained value.
47 // If the optional does not contain a value, then value() will assert.
48 inline T& value();
49 inline const T& value() const;
50
51 // value() returns the contained value, or defaultValue if the optional does
52 // not contain a value.
53 inline const T& value(const T& defaultValue) const;
54
55 // operator bool() returns true if the optional contains a value.
56 inline explicit operator bool() const noexcept;
57
58 // has_value() returns true if the optional contains a value.
59 inline bool has_value() const;
60
61 // assignment
62 inline optional& operator=(const optional& other);
63 inline optional& operator=(optional&& other) noexcept;
64 template <typename U = T, typename = IsConvertibleToT<U>>
65 inline optional& operator=(U&& value);
66 template <typename U>
67 inline optional& operator=(const optional<U>& other);
68 template <typename U>
69 inline optional& operator=(optional<U>&& other);
70
71 // value access
72 inline const T* operator->() const;
73 inline T* operator->();
74 inline const T& operator*() const;
75 inline T& operator*();
76
77 private:
78 T val = {};
79 bool set = false;
80};
81
82template <typename T>
83optional<T>::optional(const optional& other) : val(other.val), set(other.set) {}
84
85template <typename T>
86optional<T>::optional(optional&& other)
87 : val(std::move(other.val)), set(other.set) {}
88
89template <typename T>
90template <typename U>
91optional<T>::optional(const optional<U>& other) : set(other.has_value()) {
92 if (set) {
93 val = static_cast<T>(other.value());
94 }
95}
96
97template <typename T>
98template <typename U>
99optional<T>::optional(optional<U>&& other) : set(other.has_value()) {
100 if (set) {
101 val = static_cast<T>(std::move(other.value()));
102 }
103}
104
105template <typename T>
106template <typename U /*= T*/, typename>
107optional<T>::optional(U&& value) : val(std::forward<U>(value)), set(true) {}
108
109template <typename T>
110T& optional<T>::value() {
111 assert(set);
112 return val;
113}
114
115template <typename T>
116const T& optional<T>::value() const {
117 assert(set);
118 return val;
119}
120
121template <typename T>
122const T& optional<T>::value(const T& defaultValue) const {
123 if (!has_value()) {
124 return defaultValue;
125 }
126 return val;
127}
128
129template <typename T>
130optional<T>::operator bool() const noexcept {
131 return set;
132}
133
134template <typename T>
135bool optional<T>::has_value() const {
136 return set;
137}
138
139template <typename T>
140optional<T>& optional<T>::operator=(const optional& other) {
141 val = other.val;
142 set = other.set;
143 return *this;
144}
145
146template <typename T>
147optional<T>& optional<T>::operator=(optional&& other) noexcept {
148 val = std::move(other.val);
149 set = other.set;
150 return *this;
151}
152
153template <typename T>
154template <typename U /* = T */, typename>
155optional<T>& optional<T>::operator=(U&& value) {
156 val = std::forward<U>(value);
157 set = true;
158 return *this;
159}
160
161template <typename T>
162template <typename U>
163optional<T>& optional<T>::operator=(const optional<U>& other) {
164 val = other.val;
165 set = other.set;
166 return *this;
167}
168
169template <typename T>
170template <typename U>
171optional<T>& optional<T>::operator=(optional<U>&& other) {
172 val = std::move(other.val);
173 set = other.set;
174 return *this;
175}
176
177template <typename T>
178const T* optional<T>::operator->() const {
179 assert(set);
180 return &val;
181}
182
183template <typename T>
184T* optional<T>::operator->() {
185 assert(set);
186 return &val;
187}
188
189template <typename T>
190const T& optional<T>::operator*() const {
191 assert(set);
192 return val;
193}
194
195template <typename T>
196T& optional<T>::operator*() {
197 assert(set);
198 return val;
199}
200
201template <class T, class U>
202inline bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
203 if (!lhs.has_value() && !rhs.has_value()) {
204 return true;
205 }
206 if (!lhs.has_value() || !rhs.has_value()) {
207 return false;
208 }
209 return lhs.value() == rhs.value();
210}
211
212template <class T, class U>
213inline bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
214 return !(lhs == rhs);
215}
216
217template <class T, class U>
218inline bool operator<(const optional<T>& lhs, const optional<U>& rhs) {
219 if (!rhs.has_value()) {
220 return false;
221 }
222 if (!lhs.has_value()) {
223 return true;
224 }
225 return lhs.value() < rhs.value();
226}
227
228template <class T, class U>
229inline bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {
230 if (!lhs.has_value()) {
231 return true;
232 }
233 if (!rhs.has_value()) {
234 return false;
235 }
236 return lhs.value() <= rhs.value();
237}
238
239template <class T, class U>
240inline bool operator>(const optional<T>& lhs, const optional<U>& rhs) {
241 if (!lhs.has_value()) {
242 return false;
243 }
244 if (!rhs.has_value()) {
245 return true;
246 }
247 return lhs.value() > rhs.value();
248}
249
250template <class T, class U>
251inline bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {
252 if (!rhs.has_value()) {
253 return true;
254 }
255 if (!lhs.has_value()) {
256 return false;
257 }
258 return lhs.value() >= rhs.value();
259}
260
261} // namespace dap
262
263#endif // dap_optional_h
264