blob: 34e36fabebd6307c900e23520a8a8aa1a34e6d26 [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>
Hidehiko Abe5134ab382018-01-08 09:38:1636struct OptionalStorageBase {
alshabalina637f252016-10-26 22:29:2837 // Initializing |empty_| here instead of using default member initializing
38 // to avoid errors in g++ 4.8.
Hidehiko Abe5134ab382018-01-08 09:38:1639 constexpr OptionalStorageBase() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4140
alshabalin9494e4542016-10-25 09:56:4141 template <class... Args>
Hidehiko Abe5134ab382018-01-08 09:38:1642 constexpr explicit OptionalStorageBase(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.
Hidehiko Abef1c87892018-01-19 23:50:2447 // Note that this hides the (implicitly declared) move constructor, which
48 // would be used for constexpr move constructor in OptionalStorage<T>.
49 // It is needed iff T is trivially move constructible. However, the current
50 // is_trivially_{copy,move}_constructible implementation requires
51 // is_trivially_destructible (which looks a bug, cf:
52 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
53 // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
54 // necessary for this case at the moment. Please see also the destructor
55 // comment in "is_trivially_destructible = true" specialization below.
Hidehiko Abe5134ab382018-01-08 09:38:1656 ~OptionalStorageBase() {
alshabalinf06b07df2016-05-27 08:01:3157 if (!is_null_)
kwiberg882859a2016-08-16 09:42:2158 value_.~T();
alshabalinf06b07df2016-05-27 08:01:3159 }
60
Hidehiko Abe5134ab382018-01-08 09:38:1661 template <class... Args>
62 void Init(Args&&... args) {
63 DCHECK(is_null_);
64 ::new (&value_) T(std::forward<Args>(args)...);
65 is_null_ = false;
66 }
67
alshabalinf06b07df2016-05-27 08:01:3168 bool is_null_ = true;
kwiberg882859a2016-08-16 09:42:2169 union {
70 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:2871 // it doesn't contain a value. Union members must be initialized for the
72 // constructor to be 'constexpr'.
73 char empty_;
kwiberg882859a2016-08-16 09:42:2174 T value_;
75 };
alshabalinf06b07df2016-05-27 08:01:3176};
77
78template <typename T>
Hidehiko Abe5134ab382018-01-08 09:38:1679struct OptionalStorageBase<T, true /* trivially destructible */> {
alshabalina637f252016-10-26 22:29:2880 // Initializing |empty_| here instead of using default member initializing
81 // to avoid errors in g++ 4.8.
Hidehiko Abe5134ab382018-01-08 09:38:1682 constexpr OptionalStorageBase() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4183
alshabalin9494e4542016-10-25 09:56:4184 template <class... Args>
Hidehiko Abe5134ab382018-01-08 09:38:1685 constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
alshabalin9494e4542016-10-25 09:56:4186 : is_null_(false), value_(std::forward<Args>(args)...) {}
87
kwiberg882859a2016-08-16 09:42:2188 // When T is trivially destructible (i.e. its destructor does nothing) there
Hidehiko Abef1c87892018-01-19 23:50:2489 // is no need to call it. Implicitly defined destructor is trivial, because
90 // both members (bool and union containing only variants which are trivially
91 // destructible) are trivially destructible.
92 // Explicitly-defaulted destructor is also trivial, but do not use it here,
93 // because it hides the implicit move constructor. It is needed to implement
94 // constexpr move constructor in OptionalStorage iff T is trivially move
95 // constructible. Note that, if T is trivially move constructible, the move
96 // constructor of OptionalStorageBase<T> is also implicitly defined and it is
97 // trivially move constructor. If T is not trivially move constructible,
98 // "not declaring move constructor without destructor declaration" here means
99 // "delete move constructor", which works because any move constructor of
100 // OptionalStorage will not refer to it in that case.
Hidehiko Abe5134ab382018-01-08 09:38:16101
102 template <class... Args>
103 void Init(Args&&... args) {
104 DCHECK(is_null_);
105 ::new (&value_) T(std::forward<Args>(args)...);
106 is_null_ = false;
107 }
alshabalinf06b07df2016-05-27 08:01:31108
109 bool is_null_ = true;
kwiberg882859a2016-08-16 09:42:21110 union {
111 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:28112 // it doesn't contain a value. Union members must be initialized for the
113 // constructor to be 'constexpr'.
114 char empty_;
kwiberg882859a2016-08-16 09:42:21115 T value_;
116 };
alshabalinf06b07df2016-05-27 08:01:31117};
118
Hidehiko Abe5134ab382018-01-08 09:38:16119// Implement conditional constexpr copy and move constructors. These are
120// constexpr if is_trivially_{copy,move}_constructible<T>::value is true
121// respectively. If each is true, the corresponding constructor is defined as
122// "= default;", which generates a constexpr constructor (In this case,
123// the condition of constexpr-ness is satisfied because the base class also has
124// compiler generated constexpr {copy,move} constructors). Note that
125// placement-new is prohibited in constexpr.
126template <typename T,
127 bool = std::is_trivially_copy_constructible<T>::value,
128 bool = std::is_trivially_move_constructible<T>::value>
129struct OptionalStorage : OptionalStorageBase<T> {
130 // This is no trivially {copy,move} constructible case. Other cases are
131 // defined below as specializations.
132
133 // Accessing the members of template base class requires explicit
134 // declaration.
135 using OptionalStorageBase<T>::is_null_;
136 using OptionalStorageBase<T>::value_;
137 using OptionalStorageBase<T>::Init;
138
139 // Inherit constructors (specifically, the in_place constructor).
140 using OptionalStorageBase<T>::OptionalStorageBase;
141
142 // User defined constructor deletes the default constructor.
143 // Define it explicitly.
144 OptionalStorage() = default;
145
146 OptionalStorage(const OptionalStorage& other) {
147 if (!other.is_null_)
148 Init(other.value_);
149 }
150
151 OptionalStorage(OptionalStorage&& other) {
152 if (!other.is_null_)
153 Init(std::move(other.value_));
154 }
155};
156
157template <typename T>
158struct OptionalStorage<T,
159 true /* trivially copy constructible */,
160 false /* trivially move constructible */>
161 : OptionalStorageBase<T> {
162 using OptionalStorageBase<T>::is_null_;
163 using OptionalStorageBase<T>::value_;
164 using OptionalStorageBase<T>::Init;
165 using OptionalStorageBase<T>::OptionalStorageBase;
166
167 OptionalStorage() = default;
168 OptionalStorage(const OptionalStorage& other) = default;
169
170 OptionalStorage(OptionalStorage&& other) {
171 if (!other.is_null_)
172 Init(std::move(other.value_));
173 }
174};
175
176template <typename T>
177struct OptionalStorage<T,
178 false /* trivially copy constructible */,
179 true /* trivially move constructible */>
180 : OptionalStorageBase<T> {
181 using OptionalStorageBase<T>::is_null_;
182 using OptionalStorageBase<T>::value_;
183 using OptionalStorageBase<T>::Init;
184 using OptionalStorageBase<T>::OptionalStorageBase;
185
186 OptionalStorage() = default;
187 OptionalStorage(OptionalStorage&& other) = default;
188
189 OptionalStorage(const OptionalStorage& other) {
190 if (!other.is_null_)
191 Init(other.value_);
192 }
193};
194
195template <typename T>
196struct OptionalStorage<T,
197 true /* trivially copy constructible */,
198 true /* trivially move constructible */>
199 : OptionalStorageBase<T> {
200 // If both trivially {copy,move} constructible are true, it is not necessary
201 // to use user-defined constructors. So, just inheriting constructors
202 // from the base class works.
203 using OptionalStorageBase<T>::OptionalStorageBase;
204};
205
Hidehiko Abe25bbd5e2017-12-20 04:43:07206// Base class to support conditionally usable copy-/move- constructors
207// and assign operators.
208template <typename T>
209class OptionalBase {
210 // This class provides implementation rather than public API, so everything
211 // should be hidden. Often we use composition, but we cannot in this case
212 // because of C++ language restriction.
213 protected:
214 constexpr OptionalBase() = default;
Hidehiko Abe5134ab382018-01-08 09:38:16215 constexpr OptionalBase(const OptionalBase& other) = default;
216 constexpr OptionalBase(OptionalBase&& other) = default;
Hidehiko Abe25bbd5e2017-12-20 04:43:07217
218 template <class... Args>
219 constexpr explicit OptionalBase(in_place_t, Args&&... args)
220 : storage_(in_place, std::forward<Args>(args)...) {}
221
222 ~OptionalBase() = default;
223
224 OptionalBase& operator=(const OptionalBase& other) {
225 if (other.storage_.is_null_) {
226 FreeIfNeeded();
227 return *this;
228 }
229
230 InitOrAssign(other.storage_.value_);
231 return *this;
232 }
233
234 OptionalBase& operator=(OptionalBase&& other) {
235 if (other.storage_.is_null_) {
236 FreeIfNeeded();
237 return *this;
238 }
239
240 InitOrAssign(std::move(other.storage_.value_));
241 return *this;
242 }
243
Hidehiko Abe25bbd5e2017-12-20 04:43:07244 void InitOrAssign(const T& value) {
245 if (storage_.is_null_)
Hidehiko Abe5134ab382018-01-08 09:38:16246 storage_.Init(value);
Hidehiko Abe25bbd5e2017-12-20 04:43:07247 else
248 storage_.value_ = value;
249 }
250
251 void InitOrAssign(T&& value) {
252 if (storage_.is_null_)
Hidehiko Abe5134ab382018-01-08 09:38:16253 storage_.Init(std::move(value));
Hidehiko Abe25bbd5e2017-12-20 04:43:07254 else
255 storage_.value_ = std::move(value);
256 }
257
258 void FreeIfNeeded() {
259 if (storage_.is_null_)
260 return;
261 storage_.value_.~T();
262 storage_.is_null_ = true;
263 }
264
265 OptionalStorage<T> storage_;
266};
267
alshabalinf06b07df2016-05-27 08:01:31268} // namespace internal
269
mlamouri53f6b252016-04-19 17:27:01270// base::Optional is a Chromium version of the C++17 optional class:
271// std::optional documentation:
272// http://en.cppreference.com/w/cpp/utility/optional
273// Chromium documentation:
274// https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
275//
276// These are the differences between the specification and the implementation:
mlamouri53f6b252016-04-19 17:27:01277// - Constructors do not use 'constexpr' as it is a C++14 extension.
278// - 'constexpr' might be missing in some places for reasons specified locally.
279// - No exceptions are thrown, because they are banned from Chromium.
280// - All the non-members are in the 'base' namespace instead of 'std'.
281template <typename T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07282class Optional : public internal::OptionalBase<T> {
mlamouri53f6b252016-04-19 17:27:01283 public:
alshabalinf06b07df2016-05-27 08:01:31284 using value_type = T;
285
Hidehiko Abe25bbd5e2017-12-20 04:43:07286 // Defer default/copy/move constructor implementation to OptionalBase.
287 // TODO(hidehiko): Implement conditional enabling.
Chris Watkins091d6292017-12-13 04:25:58288 constexpr Optional() = default;
Hidehiko Abe5134ab382018-01-08 09:38:16289 constexpr Optional(const Optional& other) = default;
290 constexpr Optional(Optional&& other) = default;
alshabalin9494e4542016-10-25 09:56:41291
Hidehiko Abe25bbd5e2017-12-20 04:43:07292 constexpr Optional(nullopt_t) {}
mlamouri53f6b252016-04-19 17:27:01293
Hidehiko Abe25bbd5e2017-12-20 04:43:07294 constexpr Optional(const T& value)
295 : internal::OptionalBase<T>(in_place, value) {}
mlamouri53f6b252016-04-19 17:27:01296
Hidehiko Abe25bbd5e2017-12-20 04:43:07297 constexpr Optional(T&& value)
298 : internal::OptionalBase<T>(in_place, std::move(value)) {}
mlamouri53f6b252016-04-19 17:27:01299
300 template <class... Args>
Hidehiko Abe25bbd5e2017-12-20 04:43:07301 constexpr explicit Optional(in_place_t, Args&&... args)
302 : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
mlamouri53f6b252016-04-19 17:27:01303
jdoerrieb6e6c752018-01-03 09:13:45304 template <
305 class U,
306 class... Args,
307 class = std::enable_if_t<std::is_constructible<value_type,
308 std::initializer_list<U>&,
309 Args...>::value>>
310 constexpr explicit Optional(in_place_t,
311 std::initializer_list<U> il,
312 Args&&... args)
313 : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
314
alshabalinf06b07df2016-05-27 08:01:31315 ~Optional() = default;
mlamouri53f6b252016-04-19 17:27:01316
Hidehiko Abe25bbd5e2017-12-20 04:43:07317 // Defer copy-/move- assign operator implementation to OptionalBase.
318 // TOOD(hidehiko): Implement conditional enabling.
319 Optional& operator=(const Optional& other) = default;
320 Optional& operator=(Optional&& other) = default;
321
322 Optional& operator=(nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01323 FreeIfNeeded();
324 return *this;
325 }
326
mlamouri53f6b252016-04-19 17:27:01327 template <class U>
Andrey Kraynov976fbbd2017-09-13 17:15:44328 typename std::enable_if<std::is_same<std::decay_t<U>, T>::value,
mlamouri53f6b252016-04-19 17:27:01329 Optional&>::type
330 operator=(U&& value) {
331 InitOrAssign(std::forward<U>(value));
332 return *this;
333 }
334
Daniel Cheng429dbdc52017-10-04 15:33:56335 constexpr const T* operator->() const {
alshabalinf06b07df2016-05-27 08:01:31336 DCHECK(!storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01337 return &value();
338 }
339
Daniel Cheng429dbdc52017-10-04 15:33:56340 constexpr T* operator->() {
alshabalinf06b07df2016-05-27 08:01:31341 DCHECK(!storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01342 return &value();
343 }
344
345 constexpr const T& operator*() const& { return value(); }
346
Daniel Cheng429dbdc52017-10-04 15:33:56347 constexpr T& operator*() & { return value(); }
mlamouri53f6b252016-04-19 17:27:01348
349 constexpr const T&& operator*() const&& { return std::move(value()); }
350
Daniel Cheng429dbdc52017-10-04 15:33:56351 constexpr T&& operator*() && { return std::move(value()); }
mlamouri53f6b252016-04-19 17:27:01352
alshabalinf06b07df2016-05-27 08:01:31353 constexpr explicit operator bool() const { return !storage_.is_null_; }
mlamouri53f6b252016-04-19 17:27:01354
mlamouri26204572016-08-10 12:24:15355 constexpr bool has_value() const { return !storage_.is_null_; }
356
Daniel Cheng429dbdc52017-10-04 15:33:56357 constexpr T& value() & {
alshabalinf06b07df2016-05-27 08:01:31358 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21359 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01360 }
361
Daniel Cheng429dbdc52017-10-04 15:33:56362 constexpr const T& value() const & {
alshabalinf06b07df2016-05-27 08:01:31363 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21364 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01365 }
366
Daniel Cheng429dbdc52017-10-04 15:33:56367 constexpr T&& value() && {
alshabalinf06b07df2016-05-27 08:01:31368 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21369 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01370 }
371
Daniel Cheng429dbdc52017-10-04 15:33:56372 constexpr const T&& value() const && {
alshabalinf06b07df2016-05-27 08:01:31373 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21374 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01375 }
376
377 template <class U>
378 constexpr T value_or(U&& default_value) const& {
379 // TODO(mlamouri): add the following assert when possible:
380 // static_assert(std::is_copy_constructible<T>::value,
381 // "T must be copy constructible");
382 static_assert(std::is_convertible<U, T>::value,
383 "U must be convertible to T");
alshabalinf06b07df2016-05-27 08:01:31384 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
385 : value();
mlamouri53f6b252016-04-19 17:27:01386 }
387
388 template <class U>
389 T value_or(U&& default_value) && {
390 // TODO(mlamouri): add the following assert when possible:
391 // static_assert(std::is_move_constructible<T>::value,
392 // "T must be move constructible");
393 static_assert(std::is_convertible<U, T>::value,
394 "U must be convertible to T");
alshabalinf06b07df2016-05-27 08:01:31395 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
396 : std::move(value());
mlamouri53f6b252016-04-19 17:27:01397 }
398
399 void swap(Optional& other) {
alshabalinf06b07df2016-05-27 08:01:31400 if (storage_.is_null_ && other.storage_.is_null_)
mlamouri53f6b252016-04-19 17:27:01401 return;
402
alshabalinf06b07df2016-05-27 08:01:31403 if (storage_.is_null_ != other.storage_.is_null_) {
404 if (storage_.is_null_) {
Hidehiko Abe5134ab382018-01-08 09:38:16405 storage_.Init(std::move(other.storage_.value_));
mlamouri53f6b252016-04-19 17:27:01406 other.FreeIfNeeded();
407 } else {
Hidehiko Abe5134ab382018-01-08 09:38:16408 other.storage_.Init(std::move(storage_.value_));
mlamouri53f6b252016-04-19 17:27:01409 FreeIfNeeded();
410 }
411 return;
412 }
413
alshabalinf06b07df2016-05-27 08:01:31414 DCHECK(!storage_.is_null_ && !other.storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01415 using std::swap;
416 swap(**this, *other);
417 }
418
mlamouri26204572016-08-10 12:24:15419 void reset() {
420 FreeIfNeeded();
421 }
422
mlamouri53f6b252016-04-19 17:27:01423 template <class... Args>
424 void emplace(Args&&... args) {
425 FreeIfNeeded();
Hidehiko Abe5134ab382018-01-08 09:38:16426 storage_.Init(std::forward<Args>(args)...);
mlamouri53f6b252016-04-19 17:27:01427 }
428
jdoerrieb6e6c752018-01-03 09:13:45429 template <
430 class U,
431 class... Args,
432 class = std::enable_if_t<std::is_constructible<value_type,
433 std::initializer_list<U>&,
434 Args...>::value>>
435 T& emplace(std::initializer_list<U> il, Args&&... args) {
436 FreeIfNeeded();
Hidehiko Abe5134ab382018-01-08 09:38:16437 storage_.Init(il, std::forward<Args>(args)...);
jdoerrieb6e6c752018-01-03 09:13:45438 return storage_.value_;
439 }
440
mlamouri53f6b252016-04-19 17:27:01441 private:
Hidehiko Abe25bbd5e2017-12-20 04:43:07442 // Accessing template base class's protected member needs explicit
443 // declaration to do so.
444 using internal::OptionalBase<T>::FreeIfNeeded;
Hidehiko Abe25bbd5e2017-12-20 04:43:07445 using internal::OptionalBase<T>::InitOrAssign;
446 using internal::OptionalBase<T>::storage_;
mlamouri53f6b252016-04-19 17:27:01447};
448
Hidehiko Abe7a534c32017-12-20 10:56:26449// Here after defines comparation operators. The definition follows
450// http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
451// while bool() casting is replaced by has_value() to meet the chromium
452// style guide.
453template <class T, class U>
454constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
455 if (lhs.has_value() != rhs.has_value())
456 return false;
457 if (!lhs.has_value())
458 return true;
459 return *lhs == *rhs;
mlamouri53f6b252016-04-19 17:27:01460}
461
Hidehiko Abe7a534c32017-12-20 10:56:26462template <class T, class U>
463constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
464 if (lhs.has_value() != rhs.has_value())
465 return true;
466 if (!lhs.has_value())
467 return false;
468 return *lhs != *rhs;
mlamouri53f6b252016-04-19 17:27:01469}
470
Hidehiko Abe7a534c32017-12-20 10:56:26471template <class T, class U>
472constexpr bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
473 if (!rhs.has_value())
474 return false;
475 if (!lhs.has_value())
476 return true;
477 return *lhs < *rhs;
mlamouri53f6b252016-04-19 17:27:01478}
479
Hidehiko Abe7a534c32017-12-20 10:56:26480template <class T, class U>
481constexpr bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
482 if (!lhs.has_value())
483 return true;
484 if (!rhs.has_value())
485 return false;
486 return *lhs <= *rhs;
mlamouri53f6b252016-04-19 17:27:01487}
488
Hidehiko Abe7a534c32017-12-20 10:56:26489template <class T, class U>
490constexpr bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
491 if (!lhs.has_value())
492 return false;
493 if (!rhs.has_value())
494 return true;
495 return *lhs > *rhs;
mlamouri53f6b252016-04-19 17:27:01496}
497
Hidehiko Abe7a534c32017-12-20 10:56:26498template <class T, class U>
499constexpr bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
500 if (!rhs.has_value())
501 return true;
502 if (!lhs.has_value())
503 return false;
504 return *lhs >= *rhs;
mlamouri53f6b252016-04-19 17:27:01505}
506
507template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07508constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01509 return !opt;
510}
511
512template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07513constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01514 return !opt;
515}
516
517template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07518constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26519 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01520}
521
522template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07523constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26524 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01525}
526
527template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07528constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01529 return false;
530}
531
532template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07533constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26534 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01535}
536
537template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07538constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01539 return !opt;
540}
541
542template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07543constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01544 return true;
545}
546
547template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07548constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26549 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01550}
551
552template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07553constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01554 return false;
555}
556
557template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07558constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01559 return true;
560}
561
562template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07563constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01564 return !opt;
565}
566
Hidehiko Abe7a534c32017-12-20 10:56:26567template <class T, class U>
568constexpr bool operator==(const Optional<T>& opt, const U& value) {
569 return opt.has_value() ? *opt == value : false;
mlamouri53f6b252016-04-19 17:27:01570}
571
Hidehiko Abe7a534c32017-12-20 10:56:26572template <class T, class U>
573constexpr bool operator==(const U& value, const Optional<T>& opt) {
574 return opt.has_value() ? value == *opt : false;
mlamouri53f6b252016-04-19 17:27:01575}
576
Hidehiko Abe7a534c32017-12-20 10:56:26577template <class T, class U>
578constexpr bool operator!=(const Optional<T>& opt, const U& value) {
579 return opt.has_value() ? *opt != value : true;
mlamouri53f6b252016-04-19 17:27:01580}
581
Hidehiko Abe7a534c32017-12-20 10:56:26582template <class T, class U>
583constexpr bool operator!=(const U& value, const Optional<T>& opt) {
584 return opt.has_value() ? value != *opt : true;
mlamouri53f6b252016-04-19 17:27:01585}
586
Hidehiko Abe7a534c32017-12-20 10:56:26587template <class T, class U>
588constexpr bool operator<(const Optional<T>& opt, const U& value) {
589 return opt.has_value() ? *opt < value : true;
mlamouri53f6b252016-04-19 17:27:01590}
591
Hidehiko Abe7a534c32017-12-20 10:56:26592template <class T, class U>
593constexpr bool operator<(const U& value, const Optional<T>& opt) {
594 return opt.has_value() ? value < *opt : false;
mlamouri53f6b252016-04-19 17:27:01595}
596
Hidehiko Abe7a534c32017-12-20 10:56:26597template <class T, class U>
598constexpr bool operator<=(const Optional<T>& opt, const U& value) {
599 return opt.has_value() ? *opt <= value : true;
mlamouri53f6b252016-04-19 17:27:01600}
601
Hidehiko Abe7a534c32017-12-20 10:56:26602template <class T, class U>
603constexpr bool operator<=(const U& value, const Optional<T>& opt) {
604 return opt.has_value() ? value <= *opt : false;
mlamouri53f6b252016-04-19 17:27:01605}
606
Hidehiko Abe7a534c32017-12-20 10:56:26607template <class T, class U>
608constexpr bool operator>(const Optional<T>& opt, const U& value) {
609 return opt.has_value() ? *opt > value : false;
mlamouri53f6b252016-04-19 17:27:01610}
611
Hidehiko Abe7a534c32017-12-20 10:56:26612template <class T, class U>
613constexpr bool operator>(const U& value, const Optional<T>& opt) {
614 return opt.has_value() ? value > *opt : true;
mlamouri53f6b252016-04-19 17:27:01615}
616
Hidehiko Abe7a534c32017-12-20 10:56:26617template <class T, class U>
618constexpr bool operator>=(const Optional<T>& opt, const U& value) {
619 return opt.has_value() ? *opt >= value : false;
mlamouri53f6b252016-04-19 17:27:01620}
621
Hidehiko Abe7a534c32017-12-20 10:56:26622template <class T, class U>
623constexpr bool operator>=(const U& value, const Optional<T>& opt) {
624 return opt.has_value() ? value >= *opt : true;
mlamouri53f6b252016-04-19 17:27:01625}
626
627template <class T>
628constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
629 return Optional<typename std::decay<T>::type>(std::forward<T>(value));
630}
631
jdoerrieb6e6c752018-01-03 09:13:45632template <class T, class U, class... Args>
633constexpr Optional<T> make_optional(std::initializer_list<U> il,
634 Args&&... args) {
635 return Optional<T>(in_place, il, std::forward<Args>(args)...);
636}
637
mlamouri53f6b252016-04-19 17:27:01638template <class T>
639void swap(Optional<T>& lhs, Optional<T>& rhs) {
640 lhs.swap(rhs);
641}
642
643} // namespace base
644
645namespace std {
646
647template <class T>
648struct hash<base::Optional<T>> {
649 size_t operator()(const base::Optional<T>& opt) const {
650 return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
651 }
652};
653
654} // namespace std
655
656#endif // BASE_OPTIONAL_H_