blob: 00c5867265845befb85b029158c396fff865c448 [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:
174// - The constructor and emplace method using initializer_list are not
175// implemented because 'initializer_list' is banned from Chromium.
176// - Constructors do not use 'constexpr' as it is a C++14 extension.
177// - 'constexpr' might be missing in some places for reasons specified locally.
178// - No exceptions are thrown, because they are banned from Chromium.
179// - All the non-members are in the 'base' namespace instead of 'std'.
180template <typename T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07181class Optional : public internal::OptionalBase<T> {
mlamouri53f6b252016-04-19 17:27:01182 public:
alshabalinf06b07df2016-05-27 08:01:31183 using value_type = T;
184
Hidehiko Abe25bbd5e2017-12-20 04:43:07185 // Defer default/copy/move constructor implementation to OptionalBase.
186 // TODO(hidehiko): Implement conditional enabling.
Chris Watkins091d6292017-12-13 04:25:58187 constexpr Optional() = default;
Hidehiko Abe25bbd5e2017-12-20 04:43:07188 Optional(const Optional& other) = default;
189 Optional(Optional&& other) = default;
alshabalin9494e4542016-10-25 09:56:41190
Hidehiko Abe25bbd5e2017-12-20 04:43:07191 constexpr Optional(nullopt_t) {}
mlamouri53f6b252016-04-19 17:27:01192
Hidehiko Abe25bbd5e2017-12-20 04:43:07193 constexpr Optional(const T& value)
194 : internal::OptionalBase<T>(in_place, value) {}
mlamouri53f6b252016-04-19 17:27:01195
Hidehiko Abe25bbd5e2017-12-20 04:43:07196 constexpr Optional(T&& value)
197 : internal::OptionalBase<T>(in_place, std::move(value)) {}
mlamouri53f6b252016-04-19 17:27:01198
199 template <class... Args>
Hidehiko Abe25bbd5e2017-12-20 04:43:07200 constexpr explicit Optional(in_place_t, Args&&... args)
201 : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
mlamouri53f6b252016-04-19 17:27:01202
alshabalinf06b07df2016-05-27 08:01:31203 ~Optional() = default;
mlamouri53f6b252016-04-19 17:27:01204
Hidehiko Abe25bbd5e2017-12-20 04:43:07205 // Defer copy-/move- assign operator implementation to OptionalBase.
206 // TOOD(hidehiko): Implement conditional enabling.
207 Optional& operator=(const Optional& other) = default;
208 Optional& operator=(Optional&& other) = default;
209
210 Optional& operator=(nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01211 FreeIfNeeded();
212 return *this;
213 }
214
mlamouri53f6b252016-04-19 17:27:01215 template <class U>
Andrey Kraynov976fbbd2017-09-13 17:15:44216 typename std::enable_if<std::is_same<std::decay_t<U>, T>::value,
mlamouri53f6b252016-04-19 17:27:01217 Optional&>::type
218 operator=(U&& value) {
219 InitOrAssign(std::forward<U>(value));
220 return *this;
221 }
222
Daniel Cheng429dbdc52017-10-04 15:33:56223 constexpr const T* operator->() const {
alshabalinf06b07df2016-05-27 08:01:31224 DCHECK(!storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01225 return &value();
226 }
227
Daniel Cheng429dbdc52017-10-04 15:33:56228 constexpr T* operator->() {
alshabalinf06b07df2016-05-27 08:01:31229 DCHECK(!storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01230 return &value();
231 }
232
233 constexpr const T& operator*() const& { return value(); }
234
Daniel Cheng429dbdc52017-10-04 15:33:56235 constexpr T& operator*() & { return value(); }
mlamouri53f6b252016-04-19 17:27:01236
237 constexpr const T&& operator*() const&& { return std::move(value()); }
238
Daniel Cheng429dbdc52017-10-04 15:33:56239 constexpr T&& operator*() && { return std::move(value()); }
mlamouri53f6b252016-04-19 17:27:01240
alshabalinf06b07df2016-05-27 08:01:31241 constexpr explicit operator bool() const { return !storage_.is_null_; }
mlamouri53f6b252016-04-19 17:27:01242
mlamouri26204572016-08-10 12:24:15243 constexpr bool has_value() const { return !storage_.is_null_; }
244
Daniel Cheng429dbdc52017-10-04 15:33:56245 constexpr T& value() & {
alshabalinf06b07df2016-05-27 08:01:31246 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21247 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01248 }
249
Daniel Cheng429dbdc52017-10-04 15:33:56250 constexpr const T& value() const & {
alshabalinf06b07df2016-05-27 08:01:31251 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21252 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01253 }
254
Daniel Cheng429dbdc52017-10-04 15:33:56255 constexpr T&& value() && {
alshabalinf06b07df2016-05-27 08:01:31256 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21257 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01258 }
259
Daniel Cheng429dbdc52017-10-04 15:33:56260 constexpr const T&& value() const && {
alshabalinf06b07df2016-05-27 08:01:31261 DCHECK(!storage_.is_null_);
kwiberg882859a2016-08-16 09:42:21262 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01263 }
264
265 template <class U>
266 constexpr T value_or(U&& default_value) const& {
267 // TODO(mlamouri): add the following assert when possible:
268 // static_assert(std::is_copy_constructible<T>::value,
269 // "T must be copy constructible");
270 static_assert(std::is_convertible<U, T>::value,
271 "U must be convertible to T");
alshabalinf06b07df2016-05-27 08:01:31272 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
273 : value();
mlamouri53f6b252016-04-19 17:27:01274 }
275
276 template <class U>
277 T value_or(U&& default_value) && {
278 // TODO(mlamouri): add the following assert when possible:
279 // static_assert(std::is_move_constructible<T>::value,
280 // "T must be move constructible");
281 static_assert(std::is_convertible<U, T>::value,
282 "U must be convertible to T");
alshabalinf06b07df2016-05-27 08:01:31283 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
284 : std::move(value());
mlamouri53f6b252016-04-19 17:27:01285 }
286
287 void swap(Optional& other) {
alshabalinf06b07df2016-05-27 08:01:31288 if (storage_.is_null_ && other.storage_.is_null_)
mlamouri53f6b252016-04-19 17:27:01289 return;
290
alshabalinf06b07df2016-05-27 08:01:31291 if (storage_.is_null_ != other.storage_.is_null_) {
292 if (storage_.is_null_) {
kwiberg882859a2016-08-16 09:42:21293 Init(std::move(other.storage_.value_));
mlamouri53f6b252016-04-19 17:27:01294 other.FreeIfNeeded();
295 } else {
kwiberg882859a2016-08-16 09:42:21296 other.Init(std::move(storage_.value_));
mlamouri53f6b252016-04-19 17:27:01297 FreeIfNeeded();
298 }
299 return;
300 }
301
alshabalinf06b07df2016-05-27 08:01:31302 DCHECK(!storage_.is_null_ && !other.storage_.is_null_);
mlamouri53f6b252016-04-19 17:27:01303 using std::swap;
304 swap(**this, *other);
305 }
306
mlamouri26204572016-08-10 12:24:15307 void reset() {
308 FreeIfNeeded();
309 }
310
mlamouri53f6b252016-04-19 17:27:01311 template <class... Args>
312 void emplace(Args&&... args) {
313 FreeIfNeeded();
314 Init(std::forward<Args>(args)...);
315 }
316
317 private:
Hidehiko Abe25bbd5e2017-12-20 04:43:07318 // Accessing template base class's protected member needs explicit
319 // declaration to do so.
320 using internal::OptionalBase<T>::FreeIfNeeded;
321 using internal::OptionalBase<T>::Init;
322 using internal::OptionalBase<T>::InitOrAssign;
323 using internal::OptionalBase<T>::storage_;
mlamouri53f6b252016-04-19 17:27:01324};
325
Hidehiko Abe7a534c32017-12-20 10:56:26326// Here after defines comparation operators. The definition follows
327// http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
328// while bool() casting is replaced by has_value() to meet the chromium
329// style guide.
330template <class T, class U>
331constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
332 if (lhs.has_value() != rhs.has_value())
333 return false;
334 if (!lhs.has_value())
335 return true;
336 return *lhs == *rhs;
mlamouri53f6b252016-04-19 17:27:01337}
338
Hidehiko Abe7a534c32017-12-20 10:56:26339template <class T, class U>
340constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
341 if (lhs.has_value() != rhs.has_value())
342 return true;
343 if (!lhs.has_value())
344 return false;
345 return *lhs != *rhs;
mlamouri53f6b252016-04-19 17:27:01346}
347
Hidehiko Abe7a534c32017-12-20 10:56:26348template <class T, class U>
349constexpr bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
350 if (!rhs.has_value())
351 return false;
352 if (!lhs.has_value())
353 return true;
354 return *lhs < *rhs;
mlamouri53f6b252016-04-19 17:27:01355}
356
Hidehiko Abe7a534c32017-12-20 10:56:26357template <class T, class U>
358constexpr bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
359 if (!lhs.has_value())
360 return true;
361 if (!rhs.has_value())
362 return false;
363 return *lhs <= *rhs;
mlamouri53f6b252016-04-19 17:27:01364}
365
Hidehiko Abe7a534c32017-12-20 10:56:26366template <class T, class U>
367constexpr bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
368 if (!lhs.has_value())
369 return false;
370 if (!rhs.has_value())
371 return true;
372 return *lhs > *rhs;
mlamouri53f6b252016-04-19 17:27:01373}
374
Hidehiko Abe7a534c32017-12-20 10:56:26375template <class T, class U>
376constexpr bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
377 if (!rhs.has_value())
378 return true;
379 if (!lhs.has_value())
380 return false;
381 return *lhs >= *rhs;
mlamouri53f6b252016-04-19 17:27:01382}
383
384template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07385constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01386 return !opt;
387}
388
389template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07390constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01391 return !opt;
392}
393
394template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07395constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26396 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01397}
398
399template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07400constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26401 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01402}
403
404template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07405constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01406 return false;
407}
408
409template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07410constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26411 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01412}
413
414template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07415constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01416 return !opt;
417}
418
419template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07420constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01421 return true;
422}
423
424template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07425constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26426 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01427}
428
429template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07430constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01431 return false;
432}
433
434template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07435constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01436 return true;
437}
438
439template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07440constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01441 return !opt;
442}
443
Hidehiko Abe7a534c32017-12-20 10:56:26444template <class T, class U>
445constexpr bool operator==(const Optional<T>& opt, const U& value) {
446 return opt.has_value() ? *opt == value : false;
mlamouri53f6b252016-04-19 17:27:01447}
448
Hidehiko Abe7a534c32017-12-20 10:56:26449template <class T, class U>
450constexpr bool operator==(const U& value, const Optional<T>& opt) {
451 return opt.has_value() ? value == *opt : false;
mlamouri53f6b252016-04-19 17:27:01452}
453
Hidehiko Abe7a534c32017-12-20 10:56:26454template <class T, class U>
455constexpr bool operator!=(const Optional<T>& opt, const U& value) {
456 return opt.has_value() ? *opt != value : true;
mlamouri53f6b252016-04-19 17:27:01457}
458
Hidehiko Abe7a534c32017-12-20 10:56:26459template <class T, class U>
460constexpr bool operator!=(const U& value, const Optional<T>& opt) {
461 return opt.has_value() ? value != *opt : true;
mlamouri53f6b252016-04-19 17:27:01462}
463
Hidehiko Abe7a534c32017-12-20 10:56:26464template <class T, class U>
465constexpr bool operator<(const Optional<T>& opt, const U& value) {
466 return opt.has_value() ? *opt < value : true;
mlamouri53f6b252016-04-19 17:27:01467}
468
Hidehiko Abe7a534c32017-12-20 10:56:26469template <class T, class U>
470constexpr bool operator<(const U& value, const Optional<T>& opt) {
471 return opt.has_value() ? value < *opt : false;
mlamouri53f6b252016-04-19 17:27:01472}
473
Hidehiko Abe7a534c32017-12-20 10:56:26474template <class T, class U>
475constexpr bool operator<=(const Optional<T>& opt, const U& value) {
476 return opt.has_value() ? *opt <= value : true;
mlamouri53f6b252016-04-19 17:27:01477}
478
Hidehiko Abe7a534c32017-12-20 10:56:26479template <class T, class U>
480constexpr bool operator<=(const U& value, const Optional<T>& opt) {
481 return opt.has_value() ? value <= *opt : false;
mlamouri53f6b252016-04-19 17:27:01482}
483
Hidehiko Abe7a534c32017-12-20 10:56:26484template <class T, class U>
485constexpr bool operator>(const Optional<T>& opt, const U& value) {
486 return opt.has_value() ? *opt > value : false;
mlamouri53f6b252016-04-19 17:27:01487}
488
Hidehiko Abe7a534c32017-12-20 10:56:26489template <class T, class U>
490constexpr bool operator>(const U& value, const Optional<T>& opt) {
491 return opt.has_value() ? value > *opt : true;
mlamouri53f6b252016-04-19 17:27:01492}
493
Hidehiko Abe7a534c32017-12-20 10:56:26494template <class T, class U>
495constexpr bool operator>=(const Optional<T>& opt, const U& value) {
496 return opt.has_value() ? *opt >= value : false;
mlamouri53f6b252016-04-19 17:27:01497}
498
Hidehiko Abe7a534c32017-12-20 10:56:26499template <class T, class U>
500constexpr bool operator>=(const U& value, const Optional<T>& opt) {
501 return opt.has_value() ? value >= *opt : true;
mlamouri53f6b252016-04-19 17:27:01502}
503
504template <class T>
505constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
506 return Optional<typename std::decay<T>::type>(std::forward<T>(value));
507}
508
509template <class T>
510void swap(Optional<T>& lhs, Optional<T>& rhs) {
511 lhs.swap(rhs);
512}
513
514} // namespace base
515
516namespace std {
517
518template <class T>
519struct hash<base::Optional<T>> {
520 size_t operator()(const base::Optional<T>& opt) const {
521 return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
522 }
523};
524
525} // namespace std
526
527#endif // BASE_OPTIONAL_H_