blob: 36ae36fc98ba41beb4d55db3ed20e536416ef1e0 [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
Lei Zhang8618bf062019-03-25 20:37:168#include <functional>
mlamouri53f6b252016-04-19 17:27:019#include <type_traits>
Hidehiko Abe25bbd5e2017-12-20 04:43:0710#include <utility>
mlamouri53f6b252016-04-19 17:27:0111
12#include "base/logging.h"
Hidehiko Abe4d8468a2018-02-23 09:50:4113#include "base/template_util.h"
mlamouri53f6b252016-04-19 17:27:0114
15namespace base {
16
17// Specification:
mlamouri53f6b252016-04-19 17:27:0118// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
19struct nullopt_t {
20 constexpr explicit nullopt_t(int) {}
21};
22
23// Specification:
mlamouri53f6b252016-04-19 17:27:0124// http://en.cppreference.com/w/cpp/utility/optional/nullopt
25constexpr nullopt_t nullopt(0);
26
Hidehiko Abed39417a52018-01-31 03:22:4227// Forward declaration, which is refered by following helpers.
28template <typename T>
29class Optional;
30
alshabalinf06b07df2016-05-27 08:01:3131namespace internal {
32
danakj90acaf8292017-04-05 17:59:2733template <typename T, bool = std::is_trivially_destructible<T>::value>
Hidehiko Abe5134ab382018-01-08 09:38:1634struct OptionalStorageBase {
alshabalina637f252016-10-26 22:29:2835 // Initializing |empty_| here instead of using default member initializing
36 // to avoid errors in g++ 4.8.
Hidehiko Abe5134ab382018-01-08 09:38:1637 constexpr OptionalStorageBase() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4138
alshabalin9494e4542016-10-25 09:56:4139 template <class... Args>
Hidehiko Abe5134ab382018-01-08 09:38:1640 constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
Chris Blume0a5dd142018-01-24 22:35:4041 : is_populated_(true), value_(std::forward<Args>(args)...) {}
alshabalin9494e4542016-10-25 09:56:4142
alshabalinf06b07df2016-05-27 08:01:3143 // When T is not trivially destructible we must call its
44 // destructor before deallocating its memory.
Hidehiko Abef1c87892018-01-19 23:50:2445 // Note that this hides the (implicitly declared) move constructor, which
46 // would be used for constexpr move constructor in OptionalStorage<T>.
47 // It is needed iff T is trivially move constructible. However, the current
48 // is_trivially_{copy,move}_constructible implementation requires
49 // is_trivially_destructible (which looks a bug, cf:
50 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
51 // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
52 // necessary for this case at the moment. Please see also the destructor
53 // comment in "is_trivially_destructible = true" specialization below.
Hidehiko Abe5134ab382018-01-08 09:38:1654 ~OptionalStorageBase() {
Chris Blume0a5dd142018-01-24 22:35:4055 if (is_populated_)
kwiberg882859a2016-08-16 09:42:2156 value_.~T();
alshabalinf06b07df2016-05-27 08:01:3157 }
58
Hidehiko Abe5134ab382018-01-08 09:38:1659 template <class... Args>
60 void Init(Args&&... args) {
Chris Blume0a5dd142018-01-24 22:35:4061 DCHECK(!is_populated_);
Hidehiko Abe5134ab382018-01-08 09:38:1662 ::new (&value_) T(std::forward<Args>(args)...);
Chris Blume0a5dd142018-01-24 22:35:4063 is_populated_ = true;
Hidehiko Abe5134ab382018-01-08 09:38:1664 }
65
Chris Blume0a5dd142018-01-24 22:35:4066 bool is_populated_ = false;
kwiberg882859a2016-08-16 09:42:2167 union {
68 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:2869 // it doesn't contain a value. Union members must be initialized for the
70 // constructor to be 'constexpr'.
71 char empty_;
kwiberg882859a2016-08-16 09:42:2172 T value_;
73 };
alshabalinf06b07df2016-05-27 08:01:3174};
75
76template <typename T>
Hidehiko Abe5134ab382018-01-08 09:38:1677struct OptionalStorageBase<T, true /* trivially destructible */> {
alshabalina637f252016-10-26 22:29:2878 // Initializing |empty_| here instead of using default member initializing
79 // to avoid errors in g++ 4.8.
Hidehiko Abe5134ab382018-01-08 09:38:1680 constexpr OptionalStorageBase() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4181
alshabalin9494e4542016-10-25 09:56:4182 template <class... Args>
Hidehiko Abe5134ab382018-01-08 09:38:1683 constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
Chris Blume0a5dd142018-01-24 22:35:4084 : is_populated_(true), value_(std::forward<Args>(args)...) {}
alshabalin9494e4542016-10-25 09:56:4185
kwiberg882859a2016-08-16 09:42:2186 // When T is trivially destructible (i.e. its destructor does nothing) there
Hidehiko Abef1c87892018-01-19 23:50:2487 // is no need to call it. Implicitly defined destructor is trivial, because
88 // both members (bool and union containing only variants which are trivially
89 // destructible) are trivially destructible.
90 // Explicitly-defaulted destructor is also trivial, but do not use it here,
91 // because it hides the implicit move constructor. It is needed to implement
92 // constexpr move constructor in OptionalStorage iff T is trivially move
93 // constructible. Note that, if T is trivially move constructible, the move
94 // constructor of OptionalStorageBase<T> is also implicitly defined and it is
95 // trivially move constructor. If T is not trivially move constructible,
96 // "not declaring move constructor without destructor declaration" here means
97 // "delete move constructor", which works because any move constructor of
98 // OptionalStorage will not refer to it in that case.
Hidehiko Abe5134ab382018-01-08 09:38:1699
100 template <class... Args>
101 void Init(Args&&... args) {
Chris Blume0a5dd142018-01-24 22:35:40102 DCHECK(!is_populated_);
Hidehiko Abe5134ab382018-01-08 09:38:16103 ::new (&value_) T(std::forward<Args>(args)...);
Chris Blume0a5dd142018-01-24 22:35:40104 is_populated_ = true;
Hidehiko Abe5134ab382018-01-08 09:38:16105 }
alshabalinf06b07df2016-05-27 08:01:31106
Chris Blume0a5dd142018-01-24 22:35:40107 bool is_populated_ = false;
kwiberg882859a2016-08-16 09:42:21108 union {
109 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:28110 // it doesn't contain a value. Union members must be initialized for the
111 // constructor to be 'constexpr'.
112 char empty_;
kwiberg882859a2016-08-16 09:42:21113 T value_;
114 };
alshabalinf06b07df2016-05-27 08:01:31115};
116
Hidehiko Abe5134ab382018-01-08 09:38:16117// Implement conditional constexpr copy and move constructors. These are
118// constexpr if is_trivially_{copy,move}_constructible<T>::value is true
119// respectively. If each is true, the corresponding constructor is defined as
120// "= default;", which generates a constexpr constructor (In this case,
121// the condition of constexpr-ness is satisfied because the base class also has
122// compiler generated constexpr {copy,move} constructors). Note that
123// placement-new is prohibited in constexpr.
124template <typename T,
Hidehiko Abe4d8468a2018-02-23 09:50:41125 bool = is_trivially_copy_constructible<T>::value,
Hidehiko Abe5134ab382018-01-08 09:38:16126 bool = std::is_trivially_move_constructible<T>::value>
127struct OptionalStorage : OptionalStorageBase<T> {
128 // This is no trivially {copy,move} constructible case. Other cases are
129 // defined below as specializations.
130
131 // Accessing the members of template base class requires explicit
132 // declaration.
Chris Blume0a5dd142018-01-24 22:35:40133 using OptionalStorageBase<T>::is_populated_;
Hidehiko Abe5134ab382018-01-08 09:38:16134 using OptionalStorageBase<T>::value_;
135 using OptionalStorageBase<T>::Init;
136
137 // Inherit constructors (specifically, the in_place constructor).
138 using OptionalStorageBase<T>::OptionalStorageBase;
139
140 // User defined constructor deletes the default constructor.
141 // Define it explicitly.
142 OptionalStorage() = default;
143
144 OptionalStorage(const OptionalStorage& other) {
Chris Blume0a5dd142018-01-24 22:35:40145 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16146 Init(other.value_);
147 }
148
Fyodor Gayokho65eb2ba2018-03-22 18:09:21149 OptionalStorage(OptionalStorage&& other) noexcept(
150 std::is_nothrow_move_constructible<T>::value) {
Chris Blume0a5dd142018-01-24 22:35:40151 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16152 Init(std::move(other.value_));
153 }
154};
155
156template <typename T>
157struct OptionalStorage<T,
158 true /* trivially copy constructible */,
159 false /* trivially move constructible */>
160 : OptionalStorageBase<T> {
Chris Blume0a5dd142018-01-24 22:35:40161 using OptionalStorageBase<T>::is_populated_;
Hidehiko Abe5134ab382018-01-08 09:38:16162 using OptionalStorageBase<T>::value_;
163 using OptionalStorageBase<T>::Init;
164 using OptionalStorageBase<T>::OptionalStorageBase;
165
166 OptionalStorage() = default;
167 OptionalStorage(const OptionalStorage& other) = default;
168
Fyodor Gayokho65eb2ba2018-03-22 18:09:21169 OptionalStorage(OptionalStorage&& other) noexcept(
170 std::is_nothrow_move_constructible<T>::value) {
Chris Blume0a5dd142018-01-24 22:35:40171 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16172 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> {
Chris Blume0a5dd142018-01-24 22:35:40181 using OptionalStorageBase<T>::is_populated_;
Hidehiko Abe5134ab382018-01-08 09:38:16182 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) {
Chris Blume0a5dd142018-01-24 22:35:40190 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16191 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
Hidehiko Abed39417a52018-01-31 03:22:42222 // Implementation of converting constructors.
223 template <typename U>
224 explicit OptionalBase(const OptionalBase<U>& other) {
225 if (other.storage_.is_populated_)
226 storage_.Init(other.storage_.value_);
227 }
228
229 template <typename U>
230 explicit OptionalBase(OptionalBase<U>&& other) {
231 if (other.storage_.is_populated_)
232 storage_.Init(std::move(other.storage_.value_));
233 }
234
Hidehiko Abe25bbd5e2017-12-20 04:43:07235 ~OptionalBase() = default;
236
237 OptionalBase& operator=(const OptionalBase& other) {
Hidehiko Abe40ee4ae2018-02-23 04:24:12238 CopyAssign(other);
Hidehiko Abe25bbd5e2017-12-20 04:43:07239 return *this;
240 }
241
Hidehiko Abe3aa61df2018-02-24 12:47:07242 OptionalBase& operator=(OptionalBase&& other) noexcept(
243 std::is_nothrow_move_assignable<T>::value&&
244 std::is_nothrow_move_constructible<T>::value) {
Hidehiko Abe40ee4ae2018-02-23 04:24:12245 MoveAssign(std::move(other));
Hidehiko Abe25bbd5e2017-12-20 04:43:07246 return *this;
247 }
248
Hidehiko Abe40ee4ae2018-02-23 04:24:12249 template <typename U>
250 void CopyAssign(const OptionalBase<U>& other) {
251 if (other.storage_.is_populated_)
252 InitOrAssign(other.storage_.value_);
Hidehiko Abe25bbd5e2017-12-20 04:43:07253 else
Hidehiko Abe40ee4ae2018-02-23 04:24:12254 FreeIfNeeded();
Hidehiko Abe25bbd5e2017-12-20 04:43:07255 }
256
Hidehiko Abe40ee4ae2018-02-23 04:24:12257 template <typename U>
258 void MoveAssign(OptionalBase<U>&& other) {
259 if (other.storage_.is_populated_)
260 InitOrAssign(std::move(other.storage_.value_));
Hidehiko Abe25bbd5e2017-12-20 04:43:07261 else
Hidehiko Abe40ee4ae2018-02-23 04:24:12262 FreeIfNeeded();
263 }
264
265 template <typename U>
266 void InitOrAssign(U&& value) {
267 if (storage_.is_populated_)
268 storage_.value_ = std::forward<U>(value);
269 else
270 storage_.Init(std::forward<U>(value));
Hidehiko Abe25bbd5e2017-12-20 04:43:07271 }
272
Gabriel Charetted773f122019-03-19 22:06:38273 void FreeIfNeeded() {
Chris Blume0a5dd142018-01-24 22:35:40274 if (!storage_.is_populated_)
Hidehiko Abe25bbd5e2017-12-20 04:43:07275 return;
276 storage_.value_.~T();
Chris Blume0a5dd142018-01-24 22:35:40277 storage_.is_populated_ = false;
Hidehiko Abe25bbd5e2017-12-20 04:43:07278 }
279
Hidehiko Abed39417a52018-01-31 03:22:42280 // For implementing conversion, allow access to other typed OptionalBase
281 // class.
282 template <typename U>
283 friend class OptionalBase;
284
Hidehiko Abe25bbd5e2017-12-20 04:43:07285 OptionalStorage<T> storage_;
286};
287
Hidehiko Abe5cae9642018-01-26 18:01:11288// The following {Copy,Move}{Constructible,Assignable} structs are helpers to
289// implement constructor/assign-operator overloading. Specifically, if T is
290// is not movable but copyable, Optional<T>'s move constructor should not
291// participate in overload resolution. This inheritance trick implements that.
292template <bool is_copy_constructible>
293struct CopyConstructible {};
294
295template <>
296struct CopyConstructible<false> {
297 constexpr CopyConstructible() = default;
298 constexpr CopyConstructible(const CopyConstructible&) = delete;
299 constexpr CopyConstructible(CopyConstructible&&) = default;
300 CopyConstructible& operator=(const CopyConstructible&) = default;
301 CopyConstructible& operator=(CopyConstructible&&) = default;
302};
303
304template <bool is_move_constructible>
305struct MoveConstructible {};
306
307template <>
308struct MoveConstructible<false> {
309 constexpr MoveConstructible() = default;
310 constexpr MoveConstructible(const MoveConstructible&) = default;
311 constexpr MoveConstructible(MoveConstructible&&) = delete;
312 MoveConstructible& operator=(const MoveConstructible&) = default;
313 MoveConstructible& operator=(MoveConstructible&&) = default;
314};
315
316template <bool is_copy_assignable>
317struct CopyAssignable {};
318
319template <>
320struct CopyAssignable<false> {
321 constexpr CopyAssignable() = default;
322 constexpr CopyAssignable(const CopyAssignable&) = default;
323 constexpr CopyAssignable(CopyAssignable&&) = default;
324 CopyAssignable& operator=(const CopyAssignable&) = delete;
325 CopyAssignable& operator=(CopyAssignable&&) = default;
326};
327
328template <bool is_move_assignable>
329struct MoveAssignable {};
330
331template <>
332struct MoveAssignable<false> {
333 constexpr MoveAssignable() = default;
334 constexpr MoveAssignable(const MoveAssignable&) = default;
335 constexpr MoveAssignable(MoveAssignable&&) = default;
336 MoveAssignable& operator=(const MoveAssignable&) = default;
337 MoveAssignable& operator=(MoveAssignable&&) = delete;
338};
339
Hidehiko Abe40ee4ae2018-02-23 04:24:12340// Helper to conditionally enable converting constructors and assign operators.
Hidehiko Abed39417a52018-01-31 03:22:42341template <typename T, typename U>
342struct IsConvertibleFromOptional
343 : std::integral_constant<
344 bool,
345 std::is_constructible<T, Optional<U>&>::value ||
346 std::is_constructible<T, const Optional<U>&>::value ||
347 std::is_constructible<T, Optional<U>&&>::value ||
348 std::is_constructible<T, const Optional<U>&&>::value ||
349 std::is_convertible<Optional<U>&, T>::value ||
350 std::is_convertible<const Optional<U>&, T>::value ||
351 std::is_convertible<Optional<U>&&, T>::value ||
352 std::is_convertible<const Optional<U>&&, T>::value> {};
353
Hidehiko Abe40ee4ae2018-02-23 04:24:12354template <typename T, typename U>
355struct IsAssignableFromOptional
356 : std::integral_constant<
357 bool,
358 IsConvertibleFromOptional<T, U>::value ||
359 std::is_assignable<T&, Optional<U>&>::value ||
360 std::is_assignable<T&, const Optional<U>&>::value ||
361 std::is_assignable<T&, Optional<U>&&>::value ||
362 std::is_assignable<T&, const Optional<U>&&>::value> {};
363
Hidehiko Abeb467afe2018-02-23 07:01:30364// Forward compatibility for C++17.
365// Introduce one more deeper nested namespace to avoid leaking using std::swap.
366namespace swappable_impl {
367using std::swap;
368
369struct IsSwappableImpl {
370 // Tests if swap can be called. Check<T&>(0) returns true_type iff swap
371 // is available for T. Otherwise, Check's overload resolution falls back
372 // to Check(...) declared below thanks to SFINAE, so returns false_type.
373 template <typename T>
374 static auto Check(int)
375 -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
376
377 template <typename T>
378 static std::false_type Check(...);
379};
380} // namespace swappable_impl
381
382template <typename T>
383struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
384
Hidehiko Abe14f92bee2018-02-21 06:01:28385// Forward compatibility for C++20.
386template <typename T>
387using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
388
alshabalinf06b07df2016-05-27 08:01:31389} // namespace internal
390
Hidehiko Abec4aa16b2018-03-07 03:45:37391// On Windows, by default, empty-base class optimization does not work,
392// which means even if the base class is empty struct, it still consumes one
393// byte for its body. __declspec(empty_bases) enables the optimization.
394// cf)
395// https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
396#ifdef OS_WIN
397#define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
398#else
399#define OPTIONAL_DECLSPEC_EMPTY_BASES
400#endif
401
mlamouri53f6b252016-04-19 17:27:01402// base::Optional is a Chromium version of the C++17 optional class:
403// std::optional documentation:
404// http://en.cppreference.com/w/cpp/utility/optional
405// Chromium documentation:
406// https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
407//
408// These are the differences between the specification and the implementation:
mlamouri53f6b252016-04-19 17:27:01409// - Constructors do not use 'constexpr' as it is a C++14 extension.
410// - 'constexpr' might be missing in some places for reasons specified locally.
411// - No exceptions are thrown, because they are banned from Chromium.
Hidehiko Abe3aa61df2018-02-24 12:47:07412// Marked noexcept for only move constructor and move assign operators.
mlamouri53f6b252016-04-19 17:27:01413// - All the non-members are in the 'base' namespace instead of 'std'.
Hidehiko Abe14f92bee2018-02-21 06:01:28414//
415// Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
416// T's constructor (specifically via IsConvertibleFromOptional), and in the
417// check whether T can be constructible from Optional<T>, which is recursive
418// so it does not work. As of Feb 2018, std::optional C++17 implementation in
419// both clang and gcc has same limitation. MSVC SFINAE looks to have different
420// behavior, but anyway it reports an error, too.
mlamouri53f6b252016-04-19 17:27:01421template <typename T>
Hidehiko Abec4aa16b2018-03-07 03:45:37422class OPTIONAL_DECLSPEC_EMPTY_BASES Optional
Hidehiko Abe5cae9642018-01-26 18:01:11423 : public internal::OptionalBase<T>,
424 public internal::CopyConstructible<std::is_copy_constructible<T>::value>,
425 public internal::MoveConstructible<std::is_move_constructible<T>::value>,
426 public internal::CopyAssignable<std::is_copy_constructible<T>::value &&
427 std::is_copy_assignable<T>::value>,
428 public internal::MoveAssignable<std::is_move_constructible<T>::value &&
429 std::is_move_assignable<T>::value> {
Mounir Lamouri771d3e82019-06-04 00:47:31430 private:
431 // Disable some versions of T that are ill-formed.
432 // See: https://timsong-cpp.github.io/cppwp/n4659/optional#syn-1
433 static_assert(
434 !std::is_same<internal::RemoveCvRefT<T>, in_place_t>::value,
435 "instantiation of base::Optional with in_place_t is ill-formed");
436 static_assert(!std::is_same<internal::RemoveCvRefT<T>, nullopt_t>::value,
437 "instantiation of base::Optional with nullopt_t is ill-formed");
438 static_assert(
439 !std::is_reference<T>::value,
440 "instantiation of base::Optional with a reference type is ill-formed");
441 // See: https://timsong-cpp.github.io/cppwp/n4659/optional#optional-3
442 static_assert(std::is_destructible<T>::value,
443 "instantiation of base::Optional with a non-destructible type "
444 "is ill-formed");
445 // Arrays are explicitly disallowed because for arrays of known bound
446 // is_destructible is of undefined value.
447 // See: https://en.cppreference.com/w/cpp/types/is_destructible
448 static_assert(
449 !std::is_array<T>::value,
450 "instantiation of base::Optional with an array type is ill-formed");
451
mlamouri53f6b252016-04-19 17:27:01452 public:
Hidehiko Abec4aa16b2018-03-07 03:45:37453#undef OPTIONAL_DECLSPEC_EMPTY_BASES
alshabalinf06b07df2016-05-27 08:01:31454 using value_type = T;
455
Hidehiko Abe25bbd5e2017-12-20 04:43:07456 // Defer default/copy/move constructor implementation to OptionalBase.
Chris Watkins091d6292017-12-13 04:25:58457 constexpr Optional() = default;
Hidehiko Abe5134ab382018-01-08 09:38:16458 constexpr Optional(const Optional& other) = default;
Hidehiko Abe3aa61df2018-02-24 12:47:07459 constexpr Optional(Optional&& other) noexcept(
460 std::is_nothrow_move_constructible<T>::value) = default;
alshabalin9494e4542016-10-25 09:56:41461
Hidehiko Abed39417a52018-01-31 03:22:42462 constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit)
463
464 // Converting copy constructor. "explicit" only if
465 // std::is_convertible<const U&, T>::value is false. It is implemented by
466 // declaring two almost same constructors, but that condition in enable_if_t
467 // is different, so that either one is chosen, thanks to SFINAE.
468 template <
469 typename U,
470 std::enable_if_t<std::is_constructible<T, const U&>::value &&
471 !internal::IsConvertibleFromOptional<T, U>::value &&
472 std::is_convertible<const U&, T>::value,
473 bool> = false>
474 Optional(const Optional<U>& other) : internal::OptionalBase<T>(other) {}
475
476 template <
477 typename U,
478 std::enable_if_t<std::is_constructible<T, const U&>::value &&
479 !internal::IsConvertibleFromOptional<T, U>::value &&
480 !std::is_convertible<const U&, T>::value,
481 bool> = false>
482 explicit Optional(const Optional<U>& other)
483 : internal::OptionalBase<T>(other) {}
484
485 // Converting move constructor. Similar to converting copy constructor,
486 // declaring two (explicit and non-explicit) constructors.
487 template <
488 typename U,
489 std::enable_if_t<std::is_constructible<T, U&&>::value &&
490 !internal::IsConvertibleFromOptional<T, U>::value &&
491 std::is_convertible<U&&, T>::value,
492 bool> = false>
493 Optional(Optional<U>&& other) : internal::OptionalBase<T>(std::move(other)) {}
494
495 template <
496 typename U,
497 std::enable_if_t<std::is_constructible<T, U&&>::value &&
498 !internal::IsConvertibleFromOptional<T, U>::value &&
499 !std::is_convertible<U&&, T>::value,
500 bool> = false>
501 explicit Optional(Optional<U>&& other)
502 : internal::OptionalBase<T>(std::move(other)) {}
mlamouri53f6b252016-04-19 17:27:01503
mlamouri53f6b252016-04-19 17:27:01504 template <class... Args>
Hidehiko Abe25bbd5e2017-12-20 04:43:07505 constexpr explicit Optional(in_place_t, Args&&... args)
506 : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
mlamouri53f6b252016-04-19 17:27:01507
jdoerrieb6e6c752018-01-03 09:13:45508 template <
509 class U,
510 class... Args,
511 class = std::enable_if_t<std::is_constructible<value_type,
512 std::initializer_list<U>&,
513 Args...>::value>>
514 constexpr explicit Optional(in_place_t,
515 std::initializer_list<U> il,
516 Args&&... args)
517 : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
518
Hidehiko Abe14f92bee2018-02-21 06:01:28519 // Forward value constructor. Similar to converting constructors,
520 // conditionally explicit.
521 template <
522 typename U = value_type,
523 std::enable_if_t<
524 std::is_constructible<T, U&&>::value &&
525 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
526 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
527 std::is_convertible<U&&, T>::value,
528 bool> = false>
529 constexpr Optional(U&& value)
530 : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
531
532 template <
533 typename U = value_type,
534 std::enable_if_t<
535 std::is_constructible<T, U&&>::value &&
536 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
537 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
538 !std::is_convertible<U&&, T>::value,
539 bool> = false>
540 constexpr explicit Optional(U&& value)
541 : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
542
alshabalinf06b07df2016-05-27 08:01:31543 ~Optional() = default;
mlamouri53f6b252016-04-19 17:27:01544
Hidehiko Abe25bbd5e2017-12-20 04:43:07545 // Defer copy-/move- assign operator implementation to OptionalBase.
Hidehiko Abe25bbd5e2017-12-20 04:43:07546 Optional& operator=(const Optional& other) = default;
Hidehiko Abe3aa61df2018-02-24 12:47:07547 Optional& operator=(Optional&& other) noexcept(
548 std::is_nothrow_move_assignable<T>::value&&
549 std::is_nothrow_move_constructible<T>::value) = default;
Hidehiko Abe25bbd5e2017-12-20 04:43:07550
551 Optional& operator=(nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01552 FreeIfNeeded();
553 return *this;
554 }
555
Hidehiko Abe40ee4ae2018-02-23 04:24:12556 // Perfect-forwarded assignment.
557 template <typename U>
558 std::enable_if_t<
559 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
560 std::is_constructible<T, U>::value &&
561 std::is_assignable<T&, U>::value &&
562 (!std::is_scalar<T>::value ||
563 !std::is_same<std::decay_t<U>, T>::value),
564 Optional&>
mlamouri53f6b252016-04-19 17:27:01565 operator=(U&& value) {
566 InitOrAssign(std::forward<U>(value));
567 return *this;
568 }
569
Hidehiko Abe40ee4ae2018-02-23 04:24:12570 // Copy assign the state of other.
571 template <typename U>
572 std::enable_if_t<!internal::IsAssignableFromOptional<T, U>::value &&
573 std::is_constructible<T, const U&>::value &&
574 std::is_assignable<T&, const U&>::value,
575 Optional&>
576 operator=(const Optional<U>& other) {
577 CopyAssign(other);
578 return *this;
579 }
580
581 // Move assign the state of other.
582 template <typename U>
583 std::enable_if_t<!internal::IsAssignableFromOptional<T, U>::value &&
584 std::is_constructible<T, U>::value &&
585 std::is_assignable<T&, U>::value,
586 Optional&>
587 operator=(Optional<U>&& other) {
588 MoveAssign(std::move(other));
589 return *this;
590 }
591
jdoerriec85bfab2018-04-12 15:01:30592 constexpr const T* operator->() const {
Daniel Chengf24c9562019-04-09 20:40:05593 CHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30594 return &storage_.value_;
595 }
mlamouri53f6b252016-04-19 17:27:01596
jdoerriec85bfab2018-04-12 15:01:30597 constexpr T* operator->() {
Daniel Chengf24c9562019-04-09 20:40:05598 CHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30599 return &storage_.value_;
600 }
mlamouri53f6b252016-04-19 17:27:01601
jdoerriec85bfab2018-04-12 15:01:30602 constexpr const T& operator*() const & {
Daniel Chengf24c9562019-04-09 20:40:05603 CHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30604 return storage_.value_;
605 }
mlamouri53f6b252016-04-19 17:27:01606
jdoerriec85bfab2018-04-12 15:01:30607 constexpr T& operator*() & {
Daniel Chengf24c9562019-04-09 20:40:05608 CHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30609 return storage_.value_;
610 }
mlamouri53f6b252016-04-19 17:27:01611
jdoerriec85bfab2018-04-12 15:01:30612 constexpr const T&& operator*() const && {
Daniel Chengf24c9562019-04-09 20:40:05613 CHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30614 return std::move(storage_.value_);
615 }
mlamouri53f6b252016-04-19 17:27:01616
jdoerriec85bfab2018-04-12 15:01:30617 constexpr T&& operator*() && {
Daniel Chengf24c9562019-04-09 20:40:05618 CHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30619 return std::move(storage_.value_);
620 }
mlamouri53f6b252016-04-19 17:27:01621
Chris Blume0a5dd142018-01-24 22:35:40622 constexpr explicit operator bool() const { return storage_.is_populated_; }
mlamouri53f6b252016-04-19 17:27:01623
Chris Blume0a5dd142018-01-24 22:35:40624 constexpr bool has_value() const { return storage_.is_populated_; }
mlamouri26204572016-08-10 12:24:15625
Daniel Cheng429dbdc52017-10-04 15:33:56626 constexpr T& value() & {
jdoerriec85bfab2018-04-12 15:01:30627 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21628 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01629 }
630
Daniel Cheng429dbdc52017-10-04 15:33:56631 constexpr const T& value() const & {
jdoerriec85bfab2018-04-12 15:01:30632 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21633 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01634 }
635
Daniel Cheng429dbdc52017-10-04 15:33:56636 constexpr T&& value() && {
jdoerriec85bfab2018-04-12 15:01:30637 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21638 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01639 }
640
Daniel Cheng429dbdc52017-10-04 15:33:56641 constexpr const T&& value() const && {
jdoerriec85bfab2018-04-12 15:01:30642 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21643 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01644 }
645
646 template <class U>
647 constexpr T value_or(U&& default_value) const& {
648 // TODO(mlamouri): add the following assert when possible:
649 // static_assert(std::is_copy_constructible<T>::value,
650 // "T must be copy constructible");
651 static_assert(std::is_convertible<U, T>::value,
652 "U must be convertible to T");
Chris Blume0a5dd142018-01-24 22:35:40653 return storage_.is_populated_
Adam Rice289c79d2018-06-22 10:02:41654 ? storage_.value_
Chris Blume0a5dd142018-01-24 22:35:40655 : static_cast<T>(std::forward<U>(default_value));
mlamouri53f6b252016-04-19 17:27:01656 }
657
658 template <class U>
Hidehiko Abeb467afe2018-02-23 07:01:30659 constexpr T value_or(U&& default_value) && {
mlamouri53f6b252016-04-19 17:27:01660 // TODO(mlamouri): add the following assert when possible:
661 // static_assert(std::is_move_constructible<T>::value,
662 // "T must be move constructible");
663 static_assert(std::is_convertible<U, T>::value,
664 "U must be convertible to T");
Chris Blume0a5dd142018-01-24 22:35:40665 return storage_.is_populated_
Adam Rice289c79d2018-06-22 10:02:41666 ? std::move(storage_.value_)
Chris Blume0a5dd142018-01-24 22:35:40667 : static_cast<T>(std::forward<U>(default_value));
mlamouri53f6b252016-04-19 17:27:01668 }
669
670 void swap(Optional& other) {
Chris Blume0a5dd142018-01-24 22:35:40671 if (!storage_.is_populated_ && !other.storage_.is_populated_)
mlamouri53f6b252016-04-19 17:27:01672 return;
673
Chris Blume0a5dd142018-01-24 22:35:40674 if (storage_.is_populated_ != other.storage_.is_populated_) {
675 if (storage_.is_populated_) {
Hidehiko Abe5134ab382018-01-08 09:38:16676 other.storage_.Init(std::move(storage_.value_));
mlamouri53f6b252016-04-19 17:27:01677 FreeIfNeeded();
Chris Blume0a5dd142018-01-24 22:35:40678 } else {
679 storage_.Init(std::move(other.storage_.value_));
680 other.FreeIfNeeded();
mlamouri53f6b252016-04-19 17:27:01681 }
682 return;
683 }
684
Chris Blume0a5dd142018-01-24 22:35:40685 DCHECK(storage_.is_populated_ && other.storage_.is_populated_);
mlamouri53f6b252016-04-19 17:27:01686 using std::swap;
687 swap(**this, *other);
688 }
689
Hidehiko Abe3aa61df2018-02-24 12:47:07690 void reset() { FreeIfNeeded(); }
mlamouri26204572016-08-10 12:24:15691
mlamouri53f6b252016-04-19 17:27:01692 template <class... Args>
Hidehiko Abeb467afe2018-02-23 07:01:30693 T& emplace(Args&&... args) {
mlamouri53f6b252016-04-19 17:27:01694 FreeIfNeeded();
Hidehiko Abe5134ab382018-01-08 09:38:16695 storage_.Init(std::forward<Args>(args)...);
Hidehiko Abeb467afe2018-02-23 07:01:30696 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01697 }
698
Hidehiko Abeb467afe2018-02-23 07:01:30699 template <class U, class... Args>
700 std::enable_if_t<
701 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
702 T&>
703 emplace(std::initializer_list<U> il, Args&&... args) {
jdoerrieb6e6c752018-01-03 09:13:45704 FreeIfNeeded();
Hidehiko Abe5134ab382018-01-08 09:38:16705 storage_.Init(il, std::forward<Args>(args)...);
jdoerrieb6e6c752018-01-03 09:13:45706 return storage_.value_;
707 }
708
mlamouri53f6b252016-04-19 17:27:01709 private:
Hidehiko Abe25bbd5e2017-12-20 04:43:07710 // Accessing template base class's protected member needs explicit
711 // declaration to do so.
Hidehiko Abe40ee4ae2018-02-23 04:24:12712 using internal::OptionalBase<T>::CopyAssign;
Hidehiko Abe25bbd5e2017-12-20 04:43:07713 using internal::OptionalBase<T>::FreeIfNeeded;
Hidehiko Abe25bbd5e2017-12-20 04:43:07714 using internal::OptionalBase<T>::InitOrAssign;
Hidehiko Abe40ee4ae2018-02-23 04:24:12715 using internal::OptionalBase<T>::MoveAssign;
Hidehiko Abe25bbd5e2017-12-20 04:43:07716 using internal::OptionalBase<T>::storage_;
mlamouri53f6b252016-04-19 17:27:01717};
718
Hidehiko Abe7a534c32017-12-20 10:56:26719// Here after defines comparation operators. The definition follows
720// http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
721// while bool() casting is replaced by has_value() to meet the chromium
722// style guide.
723template <class T, class U>
724constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
725 if (lhs.has_value() != rhs.has_value())
726 return false;
727 if (!lhs.has_value())
728 return true;
729 return *lhs == *rhs;
mlamouri53f6b252016-04-19 17:27:01730}
731
Hidehiko Abe7a534c32017-12-20 10:56:26732template <class T, class U>
733constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
734 if (lhs.has_value() != rhs.has_value())
735 return true;
736 if (!lhs.has_value())
737 return false;
738 return *lhs != *rhs;
mlamouri53f6b252016-04-19 17:27:01739}
740
Hidehiko Abe7a534c32017-12-20 10:56:26741template <class T, class U>
742constexpr bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
743 if (!rhs.has_value())
744 return false;
745 if (!lhs.has_value())
746 return true;
747 return *lhs < *rhs;
mlamouri53f6b252016-04-19 17:27:01748}
749
Hidehiko Abe7a534c32017-12-20 10:56:26750template <class T, class U>
751constexpr bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
752 if (!lhs.has_value())
753 return true;
754 if (!rhs.has_value())
755 return false;
756 return *lhs <= *rhs;
mlamouri53f6b252016-04-19 17:27:01757}
758
Hidehiko Abe7a534c32017-12-20 10:56:26759template <class T, class U>
760constexpr bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
761 if (!lhs.has_value())
762 return false;
763 if (!rhs.has_value())
764 return true;
765 return *lhs > *rhs;
mlamouri53f6b252016-04-19 17:27:01766}
767
Hidehiko Abe7a534c32017-12-20 10:56:26768template <class T, class U>
769constexpr bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
770 if (!rhs.has_value())
771 return true;
772 if (!lhs.has_value())
773 return false;
774 return *lhs >= *rhs;
mlamouri53f6b252016-04-19 17:27:01775}
776
777template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07778constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01779 return !opt;
780}
781
782template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07783constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01784 return !opt;
785}
786
787template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07788constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26789 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01790}
791
792template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07793constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26794 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01795}
796
797template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07798constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01799 return false;
800}
801
802template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07803constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26804 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01805}
806
807template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07808constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01809 return !opt;
810}
811
812template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07813constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01814 return true;
815}
816
817template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07818constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26819 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01820}
821
822template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07823constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01824 return false;
825}
826
827template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07828constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01829 return true;
830}
831
832template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07833constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01834 return !opt;
835}
836
Hidehiko Abe7a534c32017-12-20 10:56:26837template <class T, class U>
838constexpr bool operator==(const Optional<T>& opt, const U& value) {
839 return opt.has_value() ? *opt == value : false;
mlamouri53f6b252016-04-19 17:27:01840}
841
Hidehiko Abe7a534c32017-12-20 10:56:26842template <class T, class U>
843constexpr bool operator==(const U& value, const Optional<T>& opt) {
844 return opt.has_value() ? value == *opt : false;
mlamouri53f6b252016-04-19 17:27:01845}
846
Hidehiko Abe7a534c32017-12-20 10:56:26847template <class T, class U>
848constexpr bool operator!=(const Optional<T>& opt, const U& value) {
849 return opt.has_value() ? *opt != value : true;
mlamouri53f6b252016-04-19 17:27:01850}
851
Hidehiko Abe7a534c32017-12-20 10:56:26852template <class T, class U>
853constexpr bool operator!=(const U& value, const Optional<T>& opt) {
854 return opt.has_value() ? value != *opt : true;
mlamouri53f6b252016-04-19 17:27:01855}
856
Hidehiko Abe7a534c32017-12-20 10:56:26857template <class T, class U>
858constexpr bool operator<(const Optional<T>& opt, const U& value) {
859 return opt.has_value() ? *opt < value : true;
mlamouri53f6b252016-04-19 17:27:01860}
861
Hidehiko Abe7a534c32017-12-20 10:56:26862template <class T, class U>
863constexpr bool operator<(const U& value, const Optional<T>& opt) {
864 return opt.has_value() ? value < *opt : false;
mlamouri53f6b252016-04-19 17:27:01865}
866
Hidehiko Abe7a534c32017-12-20 10:56:26867template <class T, class U>
868constexpr bool operator<=(const Optional<T>& opt, const U& value) {
869 return opt.has_value() ? *opt <= value : true;
mlamouri53f6b252016-04-19 17:27:01870}
871
Hidehiko Abe7a534c32017-12-20 10:56:26872template <class T, class U>
873constexpr bool operator<=(const U& value, const Optional<T>& opt) {
874 return opt.has_value() ? value <= *opt : false;
mlamouri53f6b252016-04-19 17:27:01875}
876
Hidehiko Abe7a534c32017-12-20 10:56:26877template <class T, class U>
878constexpr bool operator>(const Optional<T>& opt, const U& value) {
879 return opt.has_value() ? *opt > value : false;
mlamouri53f6b252016-04-19 17:27:01880}
881
Hidehiko Abe7a534c32017-12-20 10:56:26882template <class T, class U>
883constexpr bool operator>(const U& value, const Optional<T>& opt) {
884 return opt.has_value() ? value > *opt : true;
mlamouri53f6b252016-04-19 17:27:01885}
886
Hidehiko Abe7a534c32017-12-20 10:56:26887template <class T, class U>
888constexpr bool operator>=(const Optional<T>& opt, const U& value) {
889 return opt.has_value() ? *opt >= value : false;
mlamouri53f6b252016-04-19 17:27:01890}
891
Hidehiko Abe7a534c32017-12-20 10:56:26892template <class T, class U>
893constexpr bool operator>=(const U& value, const Optional<T>& opt) {
894 return opt.has_value() ? value >= *opt : true;
mlamouri53f6b252016-04-19 17:27:01895}
896
897template <class T>
Hidehiko Abeb467afe2018-02-23 07:01:30898constexpr Optional<std::decay_t<T>> make_optional(T&& value) {
899 return Optional<std::decay_t<T>>(std::forward<T>(value));
900}
901
902template <class T, class... Args>
903constexpr Optional<T> make_optional(Args&&... args) {
904 return Optional<T>(in_place, std::forward<Args>(args)...);
mlamouri53f6b252016-04-19 17:27:01905}
906
jdoerrieb6e6c752018-01-03 09:13:45907template <class T, class U, class... Args>
908constexpr Optional<T> make_optional(std::initializer_list<U> il,
909 Args&&... args) {
910 return Optional<T>(in_place, il, std::forward<Args>(args)...);
911}
912
Hidehiko Abeb467afe2018-02-23 07:01:30913// Partial specialization for a function template is not allowed. Also, it is
914// not allowed to add overload function to std namespace, while it is allowed
915// to specialize the template in std. Thus, swap() (kind of) overloading is
916// defined in base namespace, instead.
mlamouri53f6b252016-04-19 17:27:01917template <class T>
Hidehiko Abeb467afe2018-02-23 07:01:30918std::enable_if_t<std::is_move_constructible<T>::value &&
919 internal::IsSwappable<T>::value>
920swap(Optional<T>& lhs, Optional<T>& rhs) {
mlamouri53f6b252016-04-19 17:27:01921 lhs.swap(rhs);
922}
923
924} // namespace base
925
926namespace std {
927
928template <class T>
929struct hash<base::Optional<T>> {
930 size_t operator()(const base::Optional<T>& opt) const {
931 return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
932 }
933};
934
935} // namespace std
936
937#endif // BASE_OPTIONAL_H_