blob: fbc6289346005c83eec22947fcb21a0e8f88e860 [file] [log] [blame]
mlamouri53f6b252016-04-19 17:27:011// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_OPTIONAL_H_
6#define BASE_OPTIONAL_H_
7
8#include <type_traits>
Hidehiko Abe25bbd5e2017-12-20 04:43:079#include <utility>
mlamouri53f6b252016-04-19 17:27:0110
11#include "base/logging.h"
mlamouri53f6b252016-04-19 17:27:0112
13namespace base {
14
15// Specification:
16// http://en.cppreference.com/w/cpp/utility/optional/in_place_t
17struct in_place_t {};
18
19// Specification:
20// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
21struct nullopt_t {
22 constexpr explicit nullopt_t(int) {}
23};
24
25// Specification:
26// http://en.cppreference.com/w/cpp/utility/optional/in_place
27constexpr in_place_t in_place = {};
28
29// Specification:
30// http://en.cppreference.com/w/cpp/utility/optional/nullopt
31constexpr nullopt_t nullopt(0);
32
alshabalinf06b07df2016-05-27 08:01:3133namespace internal {
34
danakj90acaf8292017-04-05 17:59:2735template <typename T, bool = std::is_trivially_destructible<T>::value>
alshabalinf06b07df2016-05-27 08:01:3136struct OptionalStorage {
alshabalina637f252016-10-26 22:29:2837 // Initializing |empty_| here instead of using default member initializing
38 // to avoid errors in g++ 4.8.
39 constexpr OptionalStorage() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4140
alshabalin9494e4542016-10-25 09:56:4141 template <class... Args>
Hidehiko Abe25bbd5e2017-12-20 04:43:0742 constexpr explicit OptionalStorage(in_place_t, Args&&... args)
alshabalin9494e4542016-10-25 09:56:4143 : is_null_(false), value_(std::forward<Args>(args)...) {}
44
alshabalinf06b07df2016-05-27 08:01:3145 // When T is not trivially destructible we must call its
46 // destructor before deallocating its memory.
47 ~OptionalStorage() {
48 if (!is_null_)
kwiberg882859a2016-08-16 09:42:2149 value_.~T();
alshabalinf06b07df2016-05-27 08:01:3150 }
51
52 bool is_null_ = true;
kwiberg882859a2016-08-16 09:42:2153 union {
54 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:2855 // it doesn't contain a value. Union members must be initialized for the
56 // constructor to be 'constexpr'.
57 char empty_;
kwiberg882859a2016-08-16 09:42:2158 T value_;
59 };
alshabalinf06b07df2016-05-27 08:01:3160};
61
62template <typename T>
63struct OptionalStorage<T, true> {
alshabalina637f252016-10-26 22:29:2864 // Initializing |empty_| here instead of using default member initializing
65 // to avoid errors in g++ 4.8.
66 constexpr OptionalStorage() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4167
alshabalin9494e4542016-10-25 09:56:4168 template <class... Args>
Hidehiko Abe25bbd5e2017-12-20 04:43:0769 constexpr explicit OptionalStorage(in_place_t, Args&&... args)
alshabalin9494e4542016-10-25 09:56:4170 : is_null_(false), value_(std::forward<Args>(args)...) {}
71
kwiberg882859a2016-08-16 09:42:2172 // When T is trivially destructible (i.e. its destructor does nothing) there
73 // is no need to call it. Explicitly defaulting the destructor means it's not
74 // user-provided. Those two together make this destructor trivial.
alshabalinf06b07df2016-05-27 08:01:3175 ~OptionalStorage() = default;
76
77 bool is_null_ = true;
kwiberg882859a2016-08-16 09:42:2178 union {
79 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:2880 // it doesn't contain a value. Union members must be initialized for the
81 // constructor to be 'constexpr'.
82 char empty_;
kwiberg882859a2016-08-16 09:42:2183 T value_;
84 };
alshabalinf06b07df2016-05-27 08:01:3185};
86
Hidehiko Abe25bbd5e2017-12-20 04:43:0787// Base class to support conditionally usable copy-/move- constructors
88// and assign operators.
89template <typename T>
90class OptionalBase {
91 // This class provides implementation rather than public API, so everything
92 // should be hidden. Often we use composition, but we cannot in this case
93 // because of C++ language restriction.
94 protected:
95 constexpr OptionalBase() = default;
96
97 // TODO(dcheng): Make these constexpr iff T is trivially constructible.
98 OptionalBase(const OptionalBase& other) {
99 if (!other.storage_.is_null_)
100 Init(other.storage_.value_);
101 }
102
103 OptionalBase(OptionalBase&& other) {
104 if (!other.storage_.is_null_)
105 Init(std::move(other.storage_.value_));
106 }
107
108 template <class... Args>
109 constexpr explicit OptionalBase(in_place_t, Args&&... args)
110 : storage_(in_place, std::forward<Args>(args)...) {}
111
112 ~OptionalBase() = default;
113
114 OptionalBase& operator=(const OptionalBase& other) {
115 if (other.storage_.is_null_) {
116 FreeIfNeeded();
117 return *this;
118 }
119
120 InitOrAssign(other.storage_.value_);
121 return *this;
122 }
123
124 OptionalBase& operator=(OptionalBase&& other) {
125 if (other.storage_.is_null_) {
126 FreeIfNeeded();
127 return *this;
128 }
129
130 InitOrAssign(std::move(other.storage_.value_));
131 return *this;
132 }
133
134 template <class... Args>
135 void Init(Args&&... args) {
136 DCHECK(storage_.is_null_);
137 new (&storage_.value_) T(std::forward<Args>(args)...);
138 storage_.is_null_ = false;
139 }
140
141 void InitOrAssign(const T& value) {
142 if (storage_.is_null_)
143 Init(value);
144 else
145 storage_.value_ = value;
146 }
147
148 void InitOrAssign(T&& value) {
149 if (storage_.is_null_)
150 Init(std::move(value));
151 else
152 storage_.value_ = std::move(value);
153 }
154
155 void FreeIfNeeded() {
156 if (storage_.is_null_)
157 return;
158 storage_.value_.~T();
159 storage_.is_null_ = true;
160 }
161
162 OptionalStorage<T> storage_;
163};
164
alshabalinf06b07df2016-05-27 08:01:31165} // namespace internal
166
mlamouri53f6b252016-04-19 17:27:01167// base::Optional is a Chromium version of the C++17 optional class:
168// std::optional documentation:
169// http://en.cppreference.com/w/cpp/utility/optional
170// Chromium documentation:
171// https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
172//
173// These are the differences between the specification and the implementation:
mlamouri53f6b252016-04-19 17:27:01174// - Constructors do not use 'constexpr' as it is a C++14 extension.
175// - 'constexpr' might be missing in some places for reasons specified locally.
176// - No exceptions are thrown, because they are banned from Chromium.
177// - All the non-members are in the 'base' namespace instead of 'std'.
178template <typename T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07179class Optional : public internal::OptionalBase<T> {
mlamouri53f6b252016-04-19 17:27:01180 public:
alshabalinf06b07df2016-05-27 08:01:31181 using value_type = T;
182
Hidehiko Abe25bbd5e2017-12-20 04:43:07183 // Defer default/copy/move constructor implementation to OptionalBase.
184 // TODO(hidehiko): Implement conditional enabling.
Chris Watkins091d6292017-12-13 04:25:58185 constexpr Optional() = default;
Hidehiko Abe25bbd5e2017-12-20 04:43:07186 Optional(const Optional& other) = default;
187 Optional(Optional&& other) = default;
alshabalin9494e4542016-10-25 09:56:41188
Hidehiko Abe25bbd5e2017-12-20 04:43:07189 constexpr Optional(nullopt_t) {}
mlamouri53f6b252016-04-19 17:27:01190
Hidehiko Abe25bbd5e2017-12-20 04:43:07191 constexpr Optional(const T& value)
192 : internal::OptionalBase<T>(in_place, value) {}
mlamouri53f6b252016-04-19 17:27:01193
Hidehiko Abe25bbd5e2017-12-20 04:43:07194 constexpr Optional(T&& value)
195 : internal::OptionalBase<T>(in_place, std::move(value)) {}
mlamouri53f6b252016-04-19 17:27:01196
197 template <class... Args>
Hidehiko Abe25bbd5e2017-12-20 04:43:07198 constexpr explicit Optional(in_place_t, Args&&... args)
199 : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
mlamouri53f6b252016-04-19 17:27:01200
jdoerrieb6e6c752018-01-03 09:13:45201 template <
202 class U,
203 class... Args,
204 class = std::enable_if_t<std::is_constructible<value_type,
205 std::initializer_list<U>&,
206 Args...>::value>>
207 constexpr explicit Optional(in_place_t,
208 std::initializer_list<U> il,
209 Args&&... args)
210 : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
211
alshabalinf06b07df2016-05-27 08:01:31212 ~Optional() = default;
mlamouri53f6b252016-04-19 17:27:01213
Hidehiko Abe25bbd5e2017-12-20 04:43:07214 // Defer copy-/move- assign operator implementation to OptionalBase.
215 // TOOD(hidehiko): Implement conditional enabling.
216 Optional& operator=(const Optional& other) = default;
217 Optional& operator=(Optional&& other) = default;
218
219 Optional& operator=(nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01220 FreeIfNeeded();
221 return *this;
222 }
223
mlamouri53f6b252016-04-19 17:27:01224 template <class U>
Andrey Kraynov976fbbd2017-09-13 17:15:44225 typename std::enable_if<std::is_same<std::decay_t<U>, T>::value,
mlamouri53f6b252016-04-19 17:27:01226 Optional&>::type
227 operator=(U&& value) {
228 InitOrAssign(std::forward<U>(value));
229 return *this;
230 }
231
Daniel Cheng429dbdc52017-10-04 15:33:56232 constexpr const T* operator->() const {
alshabalinf06b07df2016-05-27 08:01:31233 DCHECK(!storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01234 return &value();
235 }
236
Daniel Cheng429dbdc52017-10-04 15:33:56237 constexpr T* operator->() {
alshabalinf06b07df2016-05-27 08:01:31238 DCHECK(!storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01239 return &value();
240 }
241
242 constexpr const T& operator*() const& { return value(); }
243
Daniel Cheng429dbdc52017-10-04 15:33:56244 constexpr T& operator*() & { return value(); }
mlamouri53f6b252016-04-19 17:27:01245
246 constexpr const T&& operator*() const&& { return std::move(value()); }
247
Daniel Cheng429dbdc52017-10-04 15:33:56248 constexpr T&& operator*() && { return std::move(value()); }
mlamouri53f6b252016-04-19 17:27:01249
alshabalinf06b07df2016-05-27 08:01:31250 constexpr explicit operator bool() const { return !storage_.is_null_; }
mlamouri53f6b252016-04-19 17:27:01251
mlamouri26204572016-08-10 12:24:15252 constexpr bool has_value() const { return !storage_.is_null_; }
253
Daniel Cheng429dbdc52017-10-04 15:33:56254 constexpr T& value() & {
alshabalinf06b07df2016-05-27 08:01:31255 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21256 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01257 }
258
Daniel Cheng429dbdc52017-10-04 15:33:56259 constexpr const T& value() const & {
alshabalinf06b07df2016-05-27 08:01:31260 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21261 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01262 }
263
Daniel Cheng429dbdc52017-10-04 15:33:56264 constexpr T&& value() && {
alshabalinf06b07df2016-05-27 08:01:31265 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21266 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01267 }
268
Daniel Cheng429dbdc52017-10-04 15:33:56269 constexpr const T&& value() const && {
alshabalinf06b07df2016-05-27 08:01:31270 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21271 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01272 }
273
274 template <class U>
275 constexpr T value_or(U&& default_value) const& {
276 // TODO(mlamouri): add the following assert when possible:
277 // static_assert(std::is_copy_constructible<T>::value,
278 // "T must be copy constructible");
279 static_assert(std::is_convertible<U, T>::value,
280 "U must be convertible to T");
alshabalinf06b07df2016-05-27 08:01:31281 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
282 : value();
mlamouri53f6b252016-04-19 17:27:01283 }
284
285 template <class U>
286 T value_or(U&& default_value) && {
287 // TODO(mlamouri): add the following assert when possible:
288 // static_assert(std::is_move_constructible<T>::value,
289 // "T must be move constructible");
290 static_assert(std::is_convertible<U, T>::value,
291 "U must be convertible to T");
alshabalinf06b07df2016-05-27 08:01:31292 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
293 : std::move(value());
mlamouri53f6b252016-04-19 17:27:01294 }
295
296 void swap(Optional& other) {
alshabalinf06b07df2016-05-27 08:01:31297 if (storage_.is_null_ && other.storage_.is_null_)
mlamouri53f6b252016-04-19 17:27:01298 return;
299
alshabalinf06b07df2016-05-27 08:01:31300 if (storage_.is_null_ != other.storage_.is_null_) {
301 if (storage_.is_null_) {
kwiberg882859a2016-08-16 09:42:21302 Init(std::move(other.storage_.value_));
mlamouri53f6b252016-04-19 17:27:01303 other.FreeIfNeeded();
304 } else {
kwiberg882859a2016-08-16 09:42:21305 other.Init(std::move(storage_.value_));
mlamouri53f6b252016-04-19 17:27:01306 FreeIfNeeded();
307 }
308 return;
309 }
310
alshabalinf06b07df2016-05-27 08:01:31311 DCHECK(!storage_.is_null_ && !other.storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01312 using std::swap;
313 swap(**this, *other);
314 }
315
mlamouri26204572016-08-10 12:24:15316 void reset() {
317 FreeIfNeeded();
318 }
319
mlamouri53f6b252016-04-19 17:27:01320 template <class... Args>
321 void emplace(Args&&... args) {
322 FreeIfNeeded();
323 Init(std::forward<Args>(args)...);
324 }
325
jdoerrieb6e6c752018-01-03 09:13:45326 template <
327 class U,
328 class... Args,
329 class = std::enable_if_t<std::is_constructible<value_type,
330 std::initializer_list<U>&,
331 Args...>::value>>
332 T& emplace(std::initializer_list<U> il, Args&&... args) {
333 FreeIfNeeded();
334 Init(il, std::forward<Args>(args)...);
335 return storage_.value_;
336 }
337
mlamouri53f6b252016-04-19 17:27:01338 private:
Hidehiko Abe25bbd5e2017-12-20 04:43:07339 // Accessing template base class's protected member needs explicit
340 // declaration to do so.
341 using internal::OptionalBase<T>::FreeIfNeeded;
342 using internal::OptionalBase<T>::Init;
343 using internal::OptionalBase<T>::InitOrAssign;
344 using internal::OptionalBase<T>::storage_;
mlamouri53f6b252016-04-19 17:27:01345};
346
Hidehiko Abe7a534c32017-12-20 10:56:26347// Here after defines comparation operators. The definition follows
348// http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
349// while bool() casting is replaced by has_value() to meet the chromium
350// style guide.
351template <class T, class U>
352constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
353 if (lhs.has_value() != rhs.has_value())
354 return false;
355 if (!lhs.has_value())
356 return true;
357 return *lhs == *rhs;
mlamouri53f6b252016-04-19 17:27:01358}
359
Hidehiko Abe7a534c32017-12-20 10:56:26360template <class T, class U>
361constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
362 if (lhs.has_value() != rhs.has_value())
363 return true;
364 if (!lhs.has_value())
365 return false;
366 return *lhs != *rhs;
mlamouri53f6b252016-04-19 17:27:01367}
368
Hidehiko Abe7a534c32017-12-20 10:56:26369template <class T, class U>
370constexpr bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
371 if (!rhs.has_value())
372 return false;
373 if (!lhs.has_value())
374 return true;
375 return *lhs < *rhs;
mlamouri53f6b252016-04-19 17:27:01376}
377
Hidehiko Abe7a534c32017-12-20 10:56:26378template <class T, class U>
379constexpr bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
380 if (!lhs.has_value())
381 return true;
382 if (!rhs.has_value())
383 return false;
384 return *lhs <= *rhs;
mlamouri53f6b252016-04-19 17:27:01385}
386
Hidehiko Abe7a534c32017-12-20 10:56:26387template <class T, class U>
388constexpr bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
389 if (!lhs.has_value())
390 return false;
391 if (!rhs.has_value())
392 return true;
393 return *lhs > *rhs;
mlamouri53f6b252016-04-19 17:27:01394}
395
Hidehiko Abe7a534c32017-12-20 10:56:26396template <class T, class U>
397constexpr bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
398 if (!rhs.has_value())
399 return true;
400 if (!lhs.has_value())
401 return false;
402 return *lhs >= *rhs;
mlamouri53f6b252016-04-19 17:27:01403}
404
405template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07406constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01407 return !opt;
408}
409
410template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07411constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01412 return !opt;
413}
414
415template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07416constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26417 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01418}
419
420template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07421constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26422 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01423}
424
425template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07426constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01427 return false;
428}
429
430template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07431constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26432 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01433}
434
435template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07436constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01437 return !opt;
438}
439
440template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07441constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01442 return true;
443}
444
445template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07446constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26447 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01448}
449
450template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07451constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01452 return false;
453}
454
455template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07456constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01457 return true;
458}
459
460template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07461constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01462 return !opt;
463}
464
Hidehiko Abe7a534c32017-12-20 10:56:26465template <class T, class U>
466constexpr bool operator==(const Optional<T>& opt, const U& value) {
467 return opt.has_value() ? *opt == value : false;
mlamouri53f6b252016-04-19 17:27:01468}
469
Hidehiko Abe7a534c32017-12-20 10:56:26470template <class T, class U>
471constexpr bool operator==(const U& value, const Optional<T>& opt) {
472 return opt.has_value() ? value == *opt : false;
mlamouri53f6b252016-04-19 17:27:01473}
474
Hidehiko Abe7a534c32017-12-20 10:56:26475template <class T, class U>
476constexpr bool operator!=(const Optional<T>& opt, const U& value) {
477 return opt.has_value() ? *opt != value : true;
mlamouri53f6b252016-04-19 17:27:01478}
479
Hidehiko Abe7a534c32017-12-20 10:56:26480template <class T, class U>
481constexpr bool operator!=(const U& value, const Optional<T>& opt) {
482 return opt.has_value() ? value != *opt : true;
mlamouri53f6b252016-04-19 17:27:01483}
484
Hidehiko Abe7a534c32017-12-20 10:56:26485template <class T, class U>
486constexpr bool operator<(const Optional<T>& opt, const U& value) {
487 return opt.has_value() ? *opt < value : true;
mlamouri53f6b252016-04-19 17:27:01488}
489
Hidehiko Abe7a534c32017-12-20 10:56:26490template <class T, class U>
491constexpr bool operator<(const U& value, const Optional<T>& opt) {
492 return opt.has_value() ? value < *opt : false;
mlamouri53f6b252016-04-19 17:27:01493}
494
Hidehiko Abe7a534c32017-12-20 10:56:26495template <class T, class U>
496constexpr bool operator<=(const Optional<T>& opt, const U& value) {
497 return opt.has_value() ? *opt <= value : true;
mlamouri53f6b252016-04-19 17:27:01498}
499
Hidehiko Abe7a534c32017-12-20 10:56:26500template <class T, class U>
501constexpr bool operator<=(const U& value, const Optional<T>& opt) {
502 return opt.has_value() ? value <= *opt : false;
mlamouri53f6b252016-04-19 17:27:01503}
504
Hidehiko Abe7a534c32017-12-20 10:56:26505template <class T, class U>
506constexpr bool operator>(const Optional<T>& opt, const U& value) {
507 return opt.has_value() ? *opt > value : false;
mlamouri53f6b252016-04-19 17:27:01508}
509
Hidehiko Abe7a534c32017-12-20 10:56:26510template <class T, class U>
511constexpr bool operator>(const U& value, const Optional<T>& opt) {
512 return opt.has_value() ? value > *opt : true;
mlamouri53f6b252016-04-19 17:27:01513}
514
Hidehiko Abe7a534c32017-12-20 10:56:26515template <class T, class U>
516constexpr bool operator>=(const Optional<T>& opt, const U& value) {
517 return opt.has_value() ? *opt >= value : false;
mlamouri53f6b252016-04-19 17:27:01518}
519
Hidehiko Abe7a534c32017-12-20 10:56:26520template <class T, class U>
521constexpr bool operator>=(const U& value, const Optional<T>& opt) {
522 return opt.has_value() ? value >= *opt : true;
mlamouri53f6b252016-04-19 17:27:01523}
524
525template <class T>
526constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
527 return Optional<typename std::decay<T>::type>(std::forward<T>(value));
528}
529
jdoerrieb6e6c752018-01-03 09:13:45530template <class T, class U, class... Args>
531constexpr Optional<T> make_optional(std::initializer_list<U> il,
532 Args&&... args) {
533 return Optional<T>(in_place, il, std::forward<Args>(args)...);
534}
535
mlamouri53f6b252016-04-19 17:27:01536template <class T>
537void swap(Optional<T>& lhs, Optional<T>& rhs) {
538 lhs.swap(rhs);
539}
540
541} // namespace base
542
543namespace std {
544
545template <class T>
546struct hash<base::Optional<T>> {
547 size_t operator()(const base::Optional<T>& opt) const {
548 return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
549 }
550};
551
552} // namespace std
553
554#endif // BASE_OPTIONAL_H_