blob: f6b1547402fc756f6822db3effd44a637a9afa9f [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"
Hidehiko Abe4d8468a2018-02-23 09:50:4112#include "base/template_util.h"
Lukasz Anforowicz5e71bd42018-09-17 19:28:5713#include "base/thread_annotations.h"
mlamouri53f6b252016-04-19 17:27:0114
15namespace base {
16
17// Specification:
18// http://en.cppreference.com/w/cpp/utility/optional/in_place_t
19struct in_place_t {};
20
21// Specification:
22// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
23struct nullopt_t {
24 constexpr explicit nullopt_t(int) {}
25};
26
27// Specification:
28// http://en.cppreference.com/w/cpp/utility/optional/in_place
29constexpr in_place_t in_place = {};
30
31// Specification:
32// http://en.cppreference.com/w/cpp/utility/optional/nullopt
33constexpr nullopt_t nullopt(0);
34
Hidehiko Abed39417a52018-01-31 03:22:4235// Forward declaration, which is refered by following helpers.
36template <typename T>
37class Optional;
38
alshabalinf06b07df2016-05-27 08:01:3139namespace internal {
40
danakj90acaf8292017-04-05 17:59:2741template <typename T, bool = std::is_trivially_destructible<T>::value>
Hidehiko Abe5134ab382018-01-08 09:38:1642struct OptionalStorageBase {
alshabalina637f252016-10-26 22:29:2843 // Initializing |empty_| here instead of using default member initializing
44 // to avoid errors in g++ 4.8.
Hidehiko Abe5134ab382018-01-08 09:38:1645 constexpr OptionalStorageBase() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4146
alshabalin9494e4542016-10-25 09:56:4147 template <class... Args>
Hidehiko Abe5134ab382018-01-08 09:38:1648 constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
Chris Blume0a5dd142018-01-24 22:35:4049 : is_populated_(true), value_(std::forward<Args>(args)...) {}
alshabalin9494e4542016-10-25 09:56:4150
alshabalinf06b07df2016-05-27 08:01:3151 // When T is not trivially destructible we must call its
52 // destructor before deallocating its memory.
Hidehiko Abef1c87892018-01-19 23:50:2453 // Note that this hides the (implicitly declared) move constructor, which
54 // would be used for constexpr move constructor in OptionalStorage<T>.
55 // It is needed iff T is trivially move constructible. However, the current
56 // is_trivially_{copy,move}_constructible implementation requires
57 // is_trivially_destructible (which looks a bug, cf:
58 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
59 // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
60 // necessary for this case at the moment. Please see also the destructor
61 // comment in "is_trivially_destructible = true" specialization below.
Hidehiko Abe5134ab382018-01-08 09:38:1662 ~OptionalStorageBase() {
Chris Blume0a5dd142018-01-24 22:35:4063 if (is_populated_)
kwiberg882859a2016-08-16 09:42:2164 value_.~T();
alshabalinf06b07df2016-05-27 08:01:3165 }
66
Hidehiko Abe5134ab382018-01-08 09:38:1667 template <class... Args>
68 void Init(Args&&... args) {
Chris Blume0a5dd142018-01-24 22:35:4069 DCHECK(!is_populated_);
Hidehiko Abe5134ab382018-01-08 09:38:1670 ::new (&value_) T(std::forward<Args>(args)...);
Chris Blume0a5dd142018-01-24 22:35:4071 is_populated_ = true;
Hidehiko Abe5134ab382018-01-08 09:38:1672 }
73
Chris Blume0a5dd142018-01-24 22:35:4074 bool is_populated_ = false;
kwiberg882859a2016-08-16 09:42:2175 union {
76 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:2877 // it doesn't contain a value. Union members must be initialized for the
78 // constructor to be 'constexpr'.
79 char empty_;
kwiberg882859a2016-08-16 09:42:2180 T value_;
81 };
alshabalinf06b07df2016-05-27 08:01:3182};
83
84template <typename T>
Hidehiko Abe5134ab382018-01-08 09:38:1685struct OptionalStorageBase<T, true /* trivially destructible */> {
alshabalina637f252016-10-26 22:29:2886 // Initializing |empty_| here instead of using default member initializing
87 // to avoid errors in g++ 4.8.
Hidehiko Abe5134ab382018-01-08 09:38:1688 constexpr OptionalStorageBase() : empty_('\0') {}
alshabalin9494e4542016-10-25 09:56:4189
alshabalin9494e4542016-10-25 09:56:4190 template <class... Args>
Hidehiko Abe5134ab382018-01-08 09:38:1691 constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
Chris Blume0a5dd142018-01-24 22:35:4092 : is_populated_(true), value_(std::forward<Args>(args)...) {}
alshabalin9494e4542016-10-25 09:56:4193
kwiberg882859a2016-08-16 09:42:2194 // When T is trivially destructible (i.e. its destructor does nothing) there
Hidehiko Abef1c87892018-01-19 23:50:2495 // is no need to call it. Implicitly defined destructor is trivial, because
96 // both members (bool and union containing only variants which are trivially
97 // destructible) are trivially destructible.
98 // Explicitly-defaulted destructor is also trivial, but do not use it here,
99 // because it hides the implicit move constructor. It is needed to implement
100 // constexpr move constructor in OptionalStorage iff T is trivially move
101 // constructible. Note that, if T is trivially move constructible, the move
102 // constructor of OptionalStorageBase<T> is also implicitly defined and it is
103 // trivially move constructor. If T is not trivially move constructible,
104 // "not declaring move constructor without destructor declaration" here means
105 // "delete move constructor", which works because any move constructor of
106 // OptionalStorage will not refer to it in that case.
Hidehiko Abe5134ab382018-01-08 09:38:16107
108 template <class... Args>
109 void Init(Args&&... args) {
Chris Blume0a5dd142018-01-24 22:35:40110 DCHECK(!is_populated_);
Hidehiko Abe5134ab382018-01-08 09:38:16111 ::new (&value_) T(std::forward<Args>(args)...);
Chris Blume0a5dd142018-01-24 22:35:40112 is_populated_ = true;
Hidehiko Abe5134ab382018-01-08 09:38:16113 }
alshabalinf06b07df2016-05-27 08:01:31114
Chris Blume0a5dd142018-01-24 22:35:40115 bool is_populated_ = false;
kwiberg882859a2016-08-16 09:42:21116 union {
117 // |empty_| exists so that the union will always be initialized, even when
alshabalina637f252016-10-26 22:29:28118 // it doesn't contain a value. Union members must be initialized for the
119 // constructor to be 'constexpr'.
120 char empty_;
kwiberg882859a2016-08-16 09:42:21121 T value_;
122 };
alshabalinf06b07df2016-05-27 08:01:31123};
124
Hidehiko Abe5134ab382018-01-08 09:38:16125// Implement conditional constexpr copy and move constructors. These are
126// constexpr if is_trivially_{copy,move}_constructible<T>::value is true
127// respectively. If each is true, the corresponding constructor is defined as
128// "= default;", which generates a constexpr constructor (In this case,
129// the condition of constexpr-ness is satisfied because the base class also has
130// compiler generated constexpr {copy,move} constructors). Note that
131// placement-new is prohibited in constexpr.
132template <typename T,
Hidehiko Abe4d8468a2018-02-23 09:50:41133 bool = is_trivially_copy_constructible<T>::value,
Hidehiko Abe5134ab382018-01-08 09:38:16134 bool = std::is_trivially_move_constructible<T>::value>
135struct OptionalStorage : OptionalStorageBase<T> {
136 // This is no trivially {copy,move} constructible case. Other cases are
137 // defined below as specializations.
138
139 // Accessing the members of template base class requires explicit
140 // declaration.
Chris Blume0a5dd142018-01-24 22:35:40141 using OptionalStorageBase<T>::is_populated_;
Hidehiko Abe5134ab382018-01-08 09:38:16142 using OptionalStorageBase<T>::value_;
143 using OptionalStorageBase<T>::Init;
144
145 // Inherit constructors (specifically, the in_place constructor).
146 using OptionalStorageBase<T>::OptionalStorageBase;
147
148 // User defined constructor deletes the default constructor.
149 // Define it explicitly.
150 OptionalStorage() = default;
151
152 OptionalStorage(const OptionalStorage& other) {
Chris Blume0a5dd142018-01-24 22:35:40153 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16154 Init(other.value_);
155 }
156
Fyodor Gayokho65eb2ba2018-03-22 18:09:21157 OptionalStorage(OptionalStorage&& other) noexcept(
158 std::is_nothrow_move_constructible<T>::value) {
Chris Blume0a5dd142018-01-24 22:35:40159 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16160 Init(std::move(other.value_));
161 }
162};
163
164template <typename T>
165struct OptionalStorage<T,
166 true /* trivially copy constructible */,
167 false /* trivially move constructible */>
168 : OptionalStorageBase<T> {
Chris Blume0a5dd142018-01-24 22:35:40169 using OptionalStorageBase<T>::is_populated_;
Hidehiko Abe5134ab382018-01-08 09:38:16170 using OptionalStorageBase<T>::value_;
171 using OptionalStorageBase<T>::Init;
172 using OptionalStorageBase<T>::OptionalStorageBase;
173
174 OptionalStorage() = default;
175 OptionalStorage(const OptionalStorage& other) = default;
176
Fyodor Gayokho65eb2ba2018-03-22 18:09:21177 OptionalStorage(OptionalStorage&& other) noexcept(
178 std::is_nothrow_move_constructible<T>::value) {
Chris Blume0a5dd142018-01-24 22:35:40179 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16180 Init(std::move(other.value_));
181 }
182};
183
184template <typename T>
185struct OptionalStorage<T,
186 false /* trivially copy constructible */,
187 true /* trivially move constructible */>
188 : OptionalStorageBase<T> {
Chris Blume0a5dd142018-01-24 22:35:40189 using OptionalStorageBase<T>::is_populated_;
Hidehiko Abe5134ab382018-01-08 09:38:16190 using OptionalStorageBase<T>::value_;
191 using OptionalStorageBase<T>::Init;
192 using OptionalStorageBase<T>::OptionalStorageBase;
193
194 OptionalStorage() = default;
195 OptionalStorage(OptionalStorage&& other) = default;
196
197 OptionalStorage(const OptionalStorage& other) {
Chris Blume0a5dd142018-01-24 22:35:40198 if (other.is_populated_)
Hidehiko Abe5134ab382018-01-08 09:38:16199 Init(other.value_);
200 }
201};
202
203template <typename T>
204struct OptionalStorage<T,
205 true /* trivially copy constructible */,
206 true /* trivially move constructible */>
207 : OptionalStorageBase<T> {
208 // If both trivially {copy,move} constructible are true, it is not necessary
209 // to use user-defined constructors. So, just inheriting constructors
210 // from the base class works.
211 using OptionalStorageBase<T>::OptionalStorageBase;
212};
213
Hidehiko Abe25bbd5e2017-12-20 04:43:07214// Base class to support conditionally usable copy-/move- constructors
215// and assign operators.
216template <typename T>
217class OptionalBase {
218 // This class provides implementation rather than public API, so everything
219 // should be hidden. Often we use composition, but we cannot in this case
220 // because of C++ language restriction.
221 protected:
222 constexpr OptionalBase() = default;
Hidehiko Abe5134ab382018-01-08 09:38:16223 constexpr OptionalBase(const OptionalBase& other) = default;
224 constexpr OptionalBase(OptionalBase&& other) = default;
Hidehiko Abe25bbd5e2017-12-20 04:43:07225
226 template <class... Args>
227 constexpr explicit OptionalBase(in_place_t, Args&&... args)
228 : storage_(in_place, std::forward<Args>(args)...) {}
229
Hidehiko Abed39417a52018-01-31 03:22:42230 // Implementation of converting constructors.
231 template <typename U>
232 explicit OptionalBase(const OptionalBase<U>& other) {
233 if (other.storage_.is_populated_)
234 storage_.Init(other.storage_.value_);
235 }
236
237 template <typename U>
238 explicit OptionalBase(OptionalBase<U>&& other) {
239 if (other.storage_.is_populated_)
240 storage_.Init(std::move(other.storage_.value_));
241 }
242
Hidehiko Abe25bbd5e2017-12-20 04:43:07243 ~OptionalBase() = default;
244
245 OptionalBase& operator=(const OptionalBase& other) {
Hidehiko Abe40ee4ae2018-02-23 04:24:12246 CopyAssign(other);
Hidehiko Abe25bbd5e2017-12-20 04:43:07247 return *this;
248 }
249
Hidehiko Abe3aa61df2018-02-24 12:47:07250 OptionalBase& operator=(OptionalBase&& other) noexcept(
251 std::is_nothrow_move_assignable<T>::value&&
252 std::is_nothrow_move_constructible<T>::value) {
Hidehiko Abe40ee4ae2018-02-23 04:24:12253 MoveAssign(std::move(other));
Hidehiko Abe25bbd5e2017-12-20 04:43:07254 return *this;
255 }
256
Hidehiko Abe40ee4ae2018-02-23 04:24:12257 template <typename U>
258 void CopyAssign(const OptionalBase<U>& other) {
259 if (other.storage_.is_populated_)
260 InitOrAssign(other.storage_.value_);
Hidehiko Abe25bbd5e2017-12-20 04:43:07261 else
Hidehiko Abe40ee4ae2018-02-23 04:24:12262 FreeIfNeeded();
Hidehiko Abe25bbd5e2017-12-20 04:43:07263 }
264
Hidehiko Abe40ee4ae2018-02-23 04:24:12265 template <typename U>
266 void MoveAssign(OptionalBase<U>&& other) {
267 if (other.storage_.is_populated_)
268 InitOrAssign(std::move(other.storage_.value_));
Hidehiko Abe25bbd5e2017-12-20 04:43:07269 else
Hidehiko Abe40ee4ae2018-02-23 04:24:12270 FreeIfNeeded();
271 }
272
273 template <typename U>
274 void InitOrAssign(U&& value) {
275 if (storage_.is_populated_)
276 storage_.value_ = std::forward<U>(value);
277 else
278 storage_.Init(std::forward<U>(value));
Hidehiko Abe25bbd5e2017-12-20 04:43:07279 }
280
Lukasz Anforowicz5e71bd42018-09-17 19:28:57281 // TODO(lukasza): Figure out how to remove the NO_THREAD_SAFETY_ANALYSIS
282 // annotation below. See https://crbug.com/881875#c1 for details.
283 void FreeIfNeeded() NO_THREAD_SAFETY_ANALYSIS {
Chris Blume0a5dd142018-01-24 22:35:40284 if (!storage_.is_populated_)
Hidehiko Abe25bbd5e2017-12-20 04:43:07285 return;
286 storage_.value_.~T();
Chris Blume0a5dd142018-01-24 22:35:40287 storage_.is_populated_ = false;
Hidehiko Abe25bbd5e2017-12-20 04:43:07288 }
289
Hidehiko Abed39417a52018-01-31 03:22:42290 // For implementing conversion, allow access to other typed OptionalBase
291 // class.
292 template <typename U>
293 friend class OptionalBase;
294
Hidehiko Abe25bbd5e2017-12-20 04:43:07295 OptionalStorage<T> storage_;
296};
297
Hidehiko Abe5cae9642018-01-26 18:01:11298// The following {Copy,Move}{Constructible,Assignable} structs are helpers to
299// implement constructor/assign-operator overloading. Specifically, if T is
300// is not movable but copyable, Optional<T>'s move constructor should not
301// participate in overload resolution. This inheritance trick implements that.
302template <bool is_copy_constructible>
303struct CopyConstructible {};
304
305template <>
306struct CopyConstructible<false> {
307 constexpr CopyConstructible() = default;
308 constexpr CopyConstructible(const CopyConstructible&) = delete;
309 constexpr CopyConstructible(CopyConstructible&&) = default;
310 CopyConstructible& operator=(const CopyConstructible&) = default;
311 CopyConstructible& operator=(CopyConstructible&&) = default;
312};
313
314template <bool is_move_constructible>
315struct MoveConstructible {};
316
317template <>
318struct MoveConstructible<false> {
319 constexpr MoveConstructible() = default;
320 constexpr MoveConstructible(const MoveConstructible&) = default;
321 constexpr MoveConstructible(MoveConstructible&&) = delete;
322 MoveConstructible& operator=(const MoveConstructible&) = default;
323 MoveConstructible& operator=(MoveConstructible&&) = default;
324};
325
326template <bool is_copy_assignable>
327struct CopyAssignable {};
328
329template <>
330struct CopyAssignable<false> {
331 constexpr CopyAssignable() = default;
332 constexpr CopyAssignable(const CopyAssignable&) = default;
333 constexpr CopyAssignable(CopyAssignable&&) = default;
334 CopyAssignable& operator=(const CopyAssignable&) = delete;
335 CopyAssignable& operator=(CopyAssignable&&) = default;
336};
337
338template <bool is_move_assignable>
339struct MoveAssignable {};
340
341template <>
342struct MoveAssignable<false> {
343 constexpr MoveAssignable() = default;
344 constexpr MoveAssignable(const MoveAssignable&) = default;
345 constexpr MoveAssignable(MoveAssignable&&) = default;
346 MoveAssignable& operator=(const MoveAssignable&) = default;
347 MoveAssignable& operator=(MoveAssignable&&) = delete;
348};
349
Hidehiko Abe40ee4ae2018-02-23 04:24:12350// Helper to conditionally enable converting constructors and assign operators.
Hidehiko Abed39417a52018-01-31 03:22:42351template <typename T, typename U>
352struct IsConvertibleFromOptional
353 : std::integral_constant<
354 bool,
355 std::is_constructible<T, Optional<U>&>::value ||
356 std::is_constructible<T, const Optional<U>&>::value ||
357 std::is_constructible<T, Optional<U>&&>::value ||
358 std::is_constructible<T, const Optional<U>&&>::value ||
359 std::is_convertible<Optional<U>&, T>::value ||
360 std::is_convertible<const Optional<U>&, T>::value ||
361 std::is_convertible<Optional<U>&&, T>::value ||
362 std::is_convertible<const Optional<U>&&, T>::value> {};
363
Hidehiko Abe40ee4ae2018-02-23 04:24:12364template <typename T, typename U>
365struct IsAssignableFromOptional
366 : std::integral_constant<
367 bool,
368 IsConvertibleFromOptional<T, U>::value ||
369 std::is_assignable<T&, Optional<U>&>::value ||
370 std::is_assignable<T&, const Optional<U>&>::value ||
371 std::is_assignable<T&, Optional<U>&&>::value ||
372 std::is_assignable<T&, const Optional<U>&&>::value> {};
373
Hidehiko Abeb467afe2018-02-23 07:01:30374// Forward compatibility for C++17.
375// Introduce one more deeper nested namespace to avoid leaking using std::swap.
376namespace swappable_impl {
377using std::swap;
378
379struct IsSwappableImpl {
380 // Tests if swap can be called. Check<T&>(0) returns true_type iff swap
381 // is available for T. Otherwise, Check's overload resolution falls back
382 // to Check(...) declared below thanks to SFINAE, so returns false_type.
383 template <typename T>
384 static auto Check(int)
385 -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
386
387 template <typename T>
388 static std::false_type Check(...);
389};
390} // namespace swappable_impl
391
392template <typename T>
393struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
394
Hidehiko Abe14f92bee2018-02-21 06:01:28395// Forward compatibility for C++20.
396template <typename T>
397using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
398
alshabalinf06b07df2016-05-27 08:01:31399} // namespace internal
400
Hidehiko Abec4aa16b2018-03-07 03:45:37401// On Windows, by default, empty-base class optimization does not work,
402// which means even if the base class is empty struct, it still consumes one
403// byte for its body. __declspec(empty_bases) enables the optimization.
404// cf)
405// https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
406#ifdef OS_WIN
407#define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
408#else
409#define OPTIONAL_DECLSPEC_EMPTY_BASES
410#endif
411
mlamouri53f6b252016-04-19 17:27:01412// base::Optional is a Chromium version of the C++17 optional class:
413// std::optional documentation:
414// http://en.cppreference.com/w/cpp/utility/optional
415// Chromium documentation:
416// https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
417//
418// These are the differences between the specification and the implementation:
mlamouri53f6b252016-04-19 17:27:01419// - Constructors do not use 'constexpr' as it is a C++14 extension.
420// - 'constexpr' might be missing in some places for reasons specified locally.
421// - No exceptions are thrown, because they are banned from Chromium.
Hidehiko Abe3aa61df2018-02-24 12:47:07422// Marked noexcept for only move constructor and move assign operators.
mlamouri53f6b252016-04-19 17:27:01423// - All the non-members are in the 'base' namespace instead of 'std'.
Hidehiko Abe14f92bee2018-02-21 06:01:28424//
425// Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
426// T's constructor (specifically via IsConvertibleFromOptional), and in the
427// check whether T can be constructible from Optional<T>, which is recursive
428// so it does not work. As of Feb 2018, std::optional C++17 implementation in
429// both clang and gcc has same limitation. MSVC SFINAE looks to have different
430// behavior, but anyway it reports an error, too.
mlamouri53f6b252016-04-19 17:27:01431template <typename T>
Hidehiko Abec4aa16b2018-03-07 03:45:37432class OPTIONAL_DECLSPEC_EMPTY_BASES Optional
Hidehiko Abe5cae9642018-01-26 18:01:11433 : public internal::OptionalBase<T>,
434 public internal::CopyConstructible<std::is_copy_constructible<T>::value>,
435 public internal::MoveConstructible<std::is_move_constructible<T>::value>,
436 public internal::CopyAssignable<std::is_copy_constructible<T>::value &&
437 std::is_copy_assignable<T>::value>,
438 public internal::MoveAssignable<std::is_move_constructible<T>::value &&
439 std::is_move_assignable<T>::value> {
mlamouri53f6b252016-04-19 17:27:01440 public:
Hidehiko Abec4aa16b2018-03-07 03:45:37441#undef OPTIONAL_DECLSPEC_EMPTY_BASES
alshabalinf06b07df2016-05-27 08:01:31442 using value_type = T;
443
Hidehiko Abe25bbd5e2017-12-20 04:43:07444 // Defer default/copy/move constructor implementation to OptionalBase.
Chris Watkins091d6292017-12-13 04:25:58445 constexpr Optional() = default;
Hidehiko Abe5134ab382018-01-08 09:38:16446 constexpr Optional(const Optional& other) = default;
Hidehiko Abe3aa61df2018-02-24 12:47:07447 constexpr Optional(Optional&& other) noexcept(
448 std::is_nothrow_move_constructible<T>::value) = default;
alshabalin9494e4542016-10-25 09:56:41449
Hidehiko Abed39417a52018-01-31 03:22:42450 constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit)
451
452 // Converting copy constructor. "explicit" only if
453 // std::is_convertible<const U&, T>::value is false. It is implemented by
454 // declaring two almost same constructors, but that condition in enable_if_t
455 // is different, so that either one is chosen, thanks to SFINAE.
456 template <
457 typename U,
458 std::enable_if_t<std::is_constructible<T, const U&>::value &&
459 !internal::IsConvertibleFromOptional<T, U>::value &&
460 std::is_convertible<const U&, T>::value,
461 bool> = false>
462 Optional(const Optional<U>& other) : internal::OptionalBase<T>(other) {}
463
464 template <
465 typename U,
466 std::enable_if_t<std::is_constructible<T, const U&>::value &&
467 !internal::IsConvertibleFromOptional<T, U>::value &&
468 !std::is_convertible<const U&, T>::value,
469 bool> = false>
470 explicit Optional(const Optional<U>& other)
471 : internal::OptionalBase<T>(other) {}
472
473 // Converting move constructor. Similar to converting copy constructor,
474 // declaring two (explicit and non-explicit) constructors.
475 template <
476 typename U,
477 std::enable_if_t<std::is_constructible<T, U&&>::value &&
478 !internal::IsConvertibleFromOptional<T, U>::value &&
479 std::is_convertible<U&&, T>::value,
480 bool> = false>
481 Optional(Optional<U>&& other) : internal::OptionalBase<T>(std::move(other)) {}
482
483 template <
484 typename U,
485 std::enable_if_t<std::is_constructible<T, U&&>::value &&
486 !internal::IsConvertibleFromOptional<T, U>::value &&
487 !std::is_convertible<U&&, T>::value,
488 bool> = false>
489 explicit Optional(Optional<U>&& other)
490 : internal::OptionalBase<T>(std::move(other)) {}
mlamouri53f6b252016-04-19 17:27:01491
mlamouri53f6b252016-04-19 17:27:01492 template <class... Args>
Hidehiko Abe25bbd5e2017-12-20 04:43:07493 constexpr explicit Optional(in_place_t, Args&&... args)
494 : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
mlamouri53f6b252016-04-19 17:27:01495
jdoerrieb6e6c752018-01-03 09:13:45496 template <
497 class U,
498 class... Args,
499 class = std::enable_if_t<std::is_constructible<value_type,
500 std::initializer_list<U>&,
501 Args...>::value>>
502 constexpr explicit Optional(in_place_t,
503 std::initializer_list<U> il,
504 Args&&... args)
505 : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
506
Hidehiko Abe14f92bee2018-02-21 06:01:28507 // Forward value constructor. Similar to converting constructors,
508 // conditionally explicit.
509 template <
510 typename U = value_type,
511 std::enable_if_t<
512 std::is_constructible<T, U&&>::value &&
513 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
514 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
515 std::is_convertible<U&&, T>::value,
516 bool> = false>
517 constexpr Optional(U&& value)
518 : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
519
520 template <
521 typename U = value_type,
522 std::enable_if_t<
523 std::is_constructible<T, U&&>::value &&
524 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
525 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
526 !std::is_convertible<U&&, T>::value,
527 bool> = false>
528 constexpr explicit Optional(U&& value)
529 : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
530
alshabalinf06b07df2016-05-27 08:01:31531 ~Optional() = default;
mlamouri53f6b252016-04-19 17:27:01532
Hidehiko Abe25bbd5e2017-12-20 04:43:07533 // Defer copy-/move- assign operator implementation to OptionalBase.
Hidehiko Abe25bbd5e2017-12-20 04:43:07534 Optional& operator=(const Optional& other) = default;
Hidehiko Abe3aa61df2018-02-24 12:47:07535 Optional& operator=(Optional&& other) noexcept(
536 std::is_nothrow_move_assignable<T>::value&&
537 std::is_nothrow_move_constructible<T>::value) = default;
Hidehiko Abe25bbd5e2017-12-20 04:43:07538
539 Optional& operator=(nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01540 FreeIfNeeded();
541 return *this;
542 }
543
Hidehiko Abe40ee4ae2018-02-23 04:24:12544 // Perfect-forwarded assignment.
545 template <typename U>
546 std::enable_if_t<
547 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
548 std::is_constructible<T, U>::value &&
549 std::is_assignable<T&, U>::value &&
550 (!std::is_scalar<T>::value ||
551 !std::is_same<std::decay_t<U>, T>::value),
552 Optional&>
mlamouri53f6b252016-04-19 17:27:01553 operator=(U&& value) {
554 InitOrAssign(std::forward<U>(value));
555 return *this;
556 }
557
Hidehiko Abe40ee4ae2018-02-23 04:24:12558 // Copy assign the state of other.
559 template <typename U>
560 std::enable_if_t<!internal::IsAssignableFromOptional<T, U>::value &&
561 std::is_constructible<T, const U&>::value &&
562 std::is_assignable<T&, const U&>::value,
563 Optional&>
564 operator=(const Optional<U>& other) {
565 CopyAssign(other);
566 return *this;
567 }
568
569 // Move assign the state of other.
570 template <typename U>
571 std::enable_if_t<!internal::IsAssignableFromOptional<T, U>::value &&
572 std::is_constructible<T, U>::value &&
573 std::is_assignable<T&, U>::value,
574 Optional&>
575 operator=(Optional<U>&& other) {
576 MoveAssign(std::move(other));
577 return *this;
578 }
579
jdoerriec85bfab2018-04-12 15:01:30580 constexpr const T* operator->() const {
jdoerriea0001012018-06-08 19:52:09581 DCHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30582 return &storage_.value_;
583 }
mlamouri53f6b252016-04-19 17:27:01584
jdoerriec85bfab2018-04-12 15:01:30585 constexpr T* operator->() {
jdoerriea0001012018-06-08 19:52:09586 DCHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30587 return &storage_.value_;
588 }
mlamouri53f6b252016-04-19 17:27:01589
jdoerriec85bfab2018-04-12 15:01:30590 constexpr const T& operator*() const & {
jdoerriea0001012018-06-08 19:52:09591 DCHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30592 return storage_.value_;
593 }
mlamouri53f6b252016-04-19 17:27:01594
jdoerriec85bfab2018-04-12 15:01:30595 constexpr T& operator*() & {
jdoerriea0001012018-06-08 19:52:09596 DCHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30597 return storage_.value_;
598 }
mlamouri53f6b252016-04-19 17:27:01599
jdoerriec85bfab2018-04-12 15:01:30600 constexpr const T&& operator*() const && {
jdoerriea0001012018-06-08 19:52:09601 DCHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30602 return std::move(storage_.value_);
603 }
mlamouri53f6b252016-04-19 17:27:01604
jdoerriec85bfab2018-04-12 15:01:30605 constexpr T&& operator*() && {
jdoerriea0001012018-06-08 19:52:09606 DCHECK(storage_.is_populated_);
jdoerriec85bfab2018-04-12 15:01:30607 return std::move(storage_.value_);
608 }
mlamouri53f6b252016-04-19 17:27:01609
Chris Blume0a5dd142018-01-24 22:35:40610 constexpr explicit operator bool() const { return storage_.is_populated_; }
mlamouri53f6b252016-04-19 17:27:01611
Chris Blume0a5dd142018-01-24 22:35:40612 constexpr bool has_value() const { return storage_.is_populated_; }
mlamouri26204572016-08-10 12:24:15613
Daniel Cheng429dbdc52017-10-04 15:33:56614 constexpr T& value() & {
jdoerriec85bfab2018-04-12 15:01:30615 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21616 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01617 }
618
Daniel Cheng429dbdc52017-10-04 15:33:56619 constexpr const T& value() const & {
jdoerriec85bfab2018-04-12 15:01:30620 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21621 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01622 }
623
Daniel Cheng429dbdc52017-10-04 15:33:56624 constexpr T&& value() && {
jdoerriec85bfab2018-04-12 15:01:30625 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21626 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01627 }
628
Daniel Cheng429dbdc52017-10-04 15:33:56629 constexpr const T&& value() const && {
jdoerriec85bfab2018-04-12 15:01:30630 CHECK(storage_.is_populated_);
kwiberg882859a2016-08-16 09:42:21631 return std::move(storage_.value_);
mlamouri53f6b252016-04-19 17:27:01632 }
633
634 template <class U>
635 constexpr T value_or(U&& default_value) const& {
636 // TODO(mlamouri): add the following assert when possible:
637 // static_assert(std::is_copy_constructible<T>::value,
638 // "T must be copy constructible");
639 static_assert(std::is_convertible<U, T>::value,
640 "U must be convertible to T");
Chris Blume0a5dd142018-01-24 22:35:40641 return storage_.is_populated_
Adam Rice289c79d2018-06-22 10:02:41642 ? storage_.value_
Chris Blume0a5dd142018-01-24 22:35:40643 : static_cast<T>(std::forward<U>(default_value));
mlamouri53f6b252016-04-19 17:27:01644 }
645
646 template <class U>
Hidehiko Abeb467afe2018-02-23 07:01:30647 constexpr T value_or(U&& default_value) && {
mlamouri53f6b252016-04-19 17:27:01648 // TODO(mlamouri): add the following assert when possible:
649 // static_assert(std::is_move_constructible<T>::value,
650 // "T must be move 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 ? std::move(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 void swap(Optional& other) {
Chris Blume0a5dd142018-01-24 22:35:40659 if (!storage_.is_populated_ && !other.storage_.is_populated_)
mlamouri53f6b252016-04-19 17:27:01660 return;
661
Chris Blume0a5dd142018-01-24 22:35:40662 if (storage_.is_populated_ != other.storage_.is_populated_) {
663 if (storage_.is_populated_) {
Hidehiko Abe5134ab382018-01-08 09:38:16664 other.storage_.Init(std::move(storage_.value_));
mlamouri53f6b252016-04-19 17:27:01665 FreeIfNeeded();
Chris Blume0a5dd142018-01-24 22:35:40666 } else {
667 storage_.Init(std::move(other.storage_.value_));
668 other.FreeIfNeeded();
mlamouri53f6b252016-04-19 17:27:01669 }
670 return;
671 }
672
Chris Blume0a5dd142018-01-24 22:35:40673 DCHECK(storage_.is_populated_ && other.storage_.is_populated_);
mlamouri53f6b252016-04-19 17:27:01674 using std::swap;
675 swap(**this, *other);
676 }
677
Hidehiko Abe3aa61df2018-02-24 12:47:07678 void reset() { FreeIfNeeded(); }
mlamouri26204572016-08-10 12:24:15679
mlamouri53f6b252016-04-19 17:27:01680 template <class... Args>
Hidehiko Abeb467afe2018-02-23 07:01:30681 T& emplace(Args&&... args) {
mlamouri53f6b252016-04-19 17:27:01682 FreeIfNeeded();
Hidehiko Abe5134ab382018-01-08 09:38:16683 storage_.Init(std::forward<Args>(args)...);
Hidehiko Abeb467afe2018-02-23 07:01:30684 return storage_.value_;
mlamouri53f6b252016-04-19 17:27:01685 }
686
Hidehiko Abeb467afe2018-02-23 07:01:30687 template <class U, class... Args>
688 std::enable_if_t<
689 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
690 T&>
691 emplace(std::initializer_list<U> il, Args&&... args) {
jdoerrieb6e6c752018-01-03 09:13:45692 FreeIfNeeded();
Hidehiko Abe5134ab382018-01-08 09:38:16693 storage_.Init(il, std::forward<Args>(args)...);
jdoerrieb6e6c752018-01-03 09:13:45694 return storage_.value_;
695 }
696
mlamouri53f6b252016-04-19 17:27:01697 private:
Hidehiko Abe25bbd5e2017-12-20 04:43:07698 // Accessing template base class's protected member needs explicit
699 // declaration to do so.
Hidehiko Abe40ee4ae2018-02-23 04:24:12700 using internal::OptionalBase<T>::CopyAssign;
Hidehiko Abe25bbd5e2017-12-20 04:43:07701 using internal::OptionalBase<T>::FreeIfNeeded;
Hidehiko Abe25bbd5e2017-12-20 04:43:07702 using internal::OptionalBase<T>::InitOrAssign;
Hidehiko Abe40ee4ae2018-02-23 04:24:12703 using internal::OptionalBase<T>::MoveAssign;
Hidehiko Abe25bbd5e2017-12-20 04:43:07704 using internal::OptionalBase<T>::storage_;
mlamouri53f6b252016-04-19 17:27:01705};
706
Hidehiko Abe7a534c32017-12-20 10:56:26707// Here after defines comparation operators. The definition follows
708// http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
709// while bool() casting is replaced by has_value() to meet the chromium
710// style guide.
711template <class T, class U>
712constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
713 if (lhs.has_value() != rhs.has_value())
714 return false;
715 if (!lhs.has_value())
716 return true;
717 return *lhs == *rhs;
mlamouri53f6b252016-04-19 17:27:01718}
719
Hidehiko Abe7a534c32017-12-20 10:56:26720template <class T, class U>
721constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
722 if (lhs.has_value() != rhs.has_value())
723 return true;
724 if (!lhs.has_value())
725 return false;
726 return *lhs != *rhs;
mlamouri53f6b252016-04-19 17:27:01727}
728
Hidehiko Abe7a534c32017-12-20 10:56:26729template <class T, class U>
730constexpr bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
731 if (!rhs.has_value())
732 return false;
733 if (!lhs.has_value())
734 return true;
735 return *lhs < *rhs;
mlamouri53f6b252016-04-19 17:27:01736}
737
Hidehiko Abe7a534c32017-12-20 10:56:26738template <class T, class U>
739constexpr bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
740 if (!lhs.has_value())
741 return true;
742 if (!rhs.has_value())
743 return false;
744 return *lhs <= *rhs;
mlamouri53f6b252016-04-19 17:27:01745}
746
Hidehiko Abe7a534c32017-12-20 10:56:26747template <class T, class U>
748constexpr bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
749 if (!lhs.has_value())
750 return false;
751 if (!rhs.has_value())
752 return true;
753 return *lhs > *rhs;
mlamouri53f6b252016-04-19 17:27:01754}
755
Hidehiko Abe7a534c32017-12-20 10:56:26756template <class T, class U>
757constexpr bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
758 if (!rhs.has_value())
759 return true;
760 if (!lhs.has_value())
761 return false;
762 return *lhs >= *rhs;
mlamouri53f6b252016-04-19 17:27:01763}
764
765template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07766constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01767 return !opt;
768}
769
770template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07771constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01772 return !opt;
773}
774
775template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07776constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26777 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01778}
779
780template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07781constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26782 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01783}
784
785template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07786constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01787 return false;
788}
789
790template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07791constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
Hidehiko Abe7a534c32017-12-20 10:56:26792 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01793}
794
795template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07796constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01797 return !opt;
798}
799
800template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07801constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01802 return true;
803}
804
805template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07806constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
Hidehiko Abe7a534c32017-12-20 10:56:26807 return opt.has_value();
mlamouri53f6b252016-04-19 17:27:01808}
809
810template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07811constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01812 return false;
813}
814
815template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07816constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
mlamouri53f6b252016-04-19 17:27:01817 return true;
818}
819
820template <class T>
Hidehiko Abe25bbd5e2017-12-20 04:43:07821constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
mlamouri53f6b252016-04-19 17:27:01822 return !opt;
823}
824
Hidehiko Abe7a534c32017-12-20 10:56:26825template <class T, class U>
826constexpr bool operator==(const Optional<T>& opt, const U& value) {
827 return opt.has_value() ? *opt == value : false;
mlamouri53f6b252016-04-19 17:27:01828}
829
Hidehiko Abe7a534c32017-12-20 10:56:26830template <class T, class U>
831constexpr bool operator==(const U& value, const Optional<T>& opt) {
832 return opt.has_value() ? value == *opt : false;
mlamouri53f6b252016-04-19 17:27:01833}
834
Hidehiko Abe7a534c32017-12-20 10:56:26835template <class T, class U>
836constexpr bool operator!=(const Optional<T>& opt, const U& value) {
837 return opt.has_value() ? *opt != value : true;
mlamouri53f6b252016-04-19 17:27:01838}
839
Hidehiko Abe7a534c32017-12-20 10:56:26840template <class T, class U>
841constexpr bool operator!=(const U& value, const Optional<T>& opt) {
842 return opt.has_value() ? value != *opt : true;
mlamouri53f6b252016-04-19 17:27:01843}
844
Hidehiko Abe7a534c32017-12-20 10:56:26845template <class T, class U>
846constexpr bool operator<(const Optional<T>& opt, const U& value) {
847 return opt.has_value() ? *opt < value : true;
mlamouri53f6b252016-04-19 17:27:01848}
849
Hidehiko Abe7a534c32017-12-20 10:56:26850template <class T, class U>
851constexpr bool operator<(const U& value, const Optional<T>& opt) {
852 return opt.has_value() ? value < *opt : false;
mlamouri53f6b252016-04-19 17:27:01853}
854
Hidehiko Abe7a534c32017-12-20 10:56:26855template <class T, class U>
856constexpr bool operator<=(const Optional<T>& opt, const U& value) {
857 return opt.has_value() ? *opt <= value : true;
mlamouri53f6b252016-04-19 17:27:01858}
859
Hidehiko Abe7a534c32017-12-20 10:56:26860template <class T, class U>
861constexpr bool operator<=(const U& value, const Optional<T>& opt) {
862 return opt.has_value() ? value <= *opt : false;
mlamouri53f6b252016-04-19 17:27:01863}
864
Hidehiko Abe7a534c32017-12-20 10:56:26865template <class T, class U>
866constexpr bool operator>(const Optional<T>& opt, const U& value) {
867 return opt.has_value() ? *opt > value : false;
mlamouri53f6b252016-04-19 17:27:01868}
869
Hidehiko Abe7a534c32017-12-20 10:56:26870template <class T, class U>
871constexpr bool operator>(const U& value, const Optional<T>& opt) {
872 return opt.has_value() ? value > *opt : true;
mlamouri53f6b252016-04-19 17:27:01873}
874
Hidehiko Abe7a534c32017-12-20 10:56:26875template <class T, class U>
876constexpr bool operator>=(const Optional<T>& opt, const U& value) {
877 return opt.has_value() ? *opt >= value : false;
mlamouri53f6b252016-04-19 17:27:01878}
879
Hidehiko Abe7a534c32017-12-20 10:56:26880template <class T, class U>
881constexpr bool operator>=(const U& value, const Optional<T>& opt) {
882 return opt.has_value() ? value >= *opt : true;
mlamouri53f6b252016-04-19 17:27:01883}
884
885template <class T>
Hidehiko Abeb467afe2018-02-23 07:01:30886constexpr Optional<std::decay_t<T>> make_optional(T&& value) {
887 return Optional<std::decay_t<T>>(std::forward<T>(value));
888}
889
890template <class T, class... Args>
891constexpr Optional<T> make_optional(Args&&... args) {
892 return Optional<T>(in_place, std::forward<Args>(args)...);
mlamouri53f6b252016-04-19 17:27:01893}
894
jdoerrieb6e6c752018-01-03 09:13:45895template <class T, class U, class... Args>
896constexpr Optional<T> make_optional(std::initializer_list<U> il,
897 Args&&... args) {
898 return Optional<T>(in_place, il, std::forward<Args>(args)...);
899}
900
Hidehiko Abeb467afe2018-02-23 07:01:30901// Partial specialization for a function template is not allowed. Also, it is
902// not allowed to add overload function to std namespace, while it is allowed
903// to specialize the template in std. Thus, swap() (kind of) overloading is
904// defined in base namespace, instead.
mlamouri53f6b252016-04-19 17:27:01905template <class T>
Hidehiko Abeb467afe2018-02-23 07:01:30906std::enable_if_t<std::is_move_constructible<T>::value &&
907 internal::IsSwappable<T>::value>
908swap(Optional<T>& lhs, Optional<T>& rhs) {
mlamouri53f6b252016-04-19 17:27:01909 lhs.swap(rhs);
910}
911
912} // namespace base
913
914namespace std {
915
916template <class T>
917struct hash<base::Optional<T>> {
918 size_t operator()(const base::Optional<T>& opt) const {
919 return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
920 }
921};
922
923} // namespace std
924
925#endif // BASE_OPTIONAL_H_