1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
9 * Optional - For conditional initialization of values, like boost::optional,
10 * but with support for move semantics and emplacement. Reference type support
11 * has not been included due to limited use cases and potential confusion with
12 * semantics of assignment: Assigning to an optional reference could quite
13 * reasonably copy its value or redirect the reference.
15 * Optional can be useful when a variable might or might not be needed:
17 * Optional<Logger> maybeLogger = ...;
19 * maybeLogger->log("hello");
22 * Optional enables a 'null' value for types which do not otherwise have
23 * nullability, especially useful for parameter passing:
25 * void testIterator(const unique_ptr<Iterator>& it,
26 * initializer_list<int> idsExpected,
27 * Optional<initializer_list<int>> ranksExpected = none) {
28 * for (int i = 0; it->next(); ++i) {
29 * EXPECT_EQ(it->doc().id(), idsExpected[i]);
30 * if (ranksExpected) {
31 * EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
36 * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
37 * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
40 * Optional<int> maybeInt = ...;
41 * if (int* v = get_pointer(maybeInt)) {
50 #include <type_traits>
53 #include <folly/CPortability.h>
54 #include <folly/Traits.h>
55 #include <folly/Utility.h>
59 template <class Value
>
63 template <class Value
>
64 struct OptionalPromiseReturn
;
68 enum class _secret
{ _token
};
71 * No default constructor to support both `op = {}` and `op = none`
72 * as syntax for clearing an Optional, just like std::nullopt_t.
74 constexpr explicit None(_secret
) {}
76 constexpr None none
{None::_secret::_token
};
78 class FOLLY_EXPORT OptionalEmptyException
: public std::runtime_error
{
80 OptionalEmptyException()
81 : std::runtime_error("Empty Optional cannot be unwrapped") {}
84 template <class Value
>
87 typedef Value value_type
;
90 !std::is_reference
<Value
>::value
,
91 "Optional may not be used with reference types");
93 !std::is_abstract
<Value
>::value
,
94 "Optional may not be used with abstract types");
96 Optional() noexcept
{}
98 Optional(const Optional
& src
) noexcept(
99 std::is_nothrow_copy_constructible
<Value
>::value
) {
100 if (src
.hasValue()) {
101 construct(src
.value());
105 Optional(Optional
&& src
) noexcept(
106 std::is_nothrow_move_constructible
<Value
>::value
) {
107 if (src
.hasValue()) {
108 construct(std::move(src
.value()));
113 /* implicit */ Optional(const None
&) noexcept
{}
115 /* implicit */ Optional(Value
&& newValue
) noexcept(
116 std::is_nothrow_move_constructible
<Value
>::value
) {
117 construct(std::move(newValue
));
120 /* implicit */ Optional(const Value
& newValue
) noexcept(
121 std::is_nothrow_copy_constructible
<Value
>::value
) {
125 template <typename
... Args
>
126 explicit Optional(in_place_t
, Args
&&... args
) noexcept(
127 std::is_nothrow_constructible
<Value
, Args
...>::value
)
128 : Optional
{PrivateConstructor
{}, std::forward
<Args
>(args
)...} {}
130 template <typename U
, typename
... Args
>
133 std::initializer_list
<U
> il
,
134 Args
&&... args
) noexcept(std::
135 is_nothrow_constructible
<
137 std::initializer_list
<U
>,
139 : Optional
{PrivateConstructor
{}, il
, std::forward
<Args
>(args
)...} {}
141 // Used only when an Optional is used with coroutines on MSVC
142 /* implicit */ Optional(const detail::OptionalPromiseReturn
<Value
>& p
)
144 p
.promise_
->value_
= this;
147 void assign(const None
&) {
151 void assign(Optional
&& src
) {
153 if (src
.hasValue()) {
154 assign(std::move(src
.value()));
162 void assign(const Optional
& src
) {
163 if (src
.hasValue()) {
170 void assign(Value
&& newValue
) {
172 storage_
.value
= std::move(newValue
);
174 construct(std::move(newValue
));
178 void assign(const Value
& newValue
) {
180 storage_
.value
= newValue
;
186 Optional
& operator=(None
) noexcept
{
192 Optional
& operator=(Arg
&& arg
) {
193 assign(std::forward
<Arg
>(arg
));
197 Optional
& operator=(Optional
&& other
) noexcept(
198 std::is_nothrow_move_assignable
<Value
>::value
) {
199 assign(std::move(other
));
203 Optional
& operator=(const Optional
& other
) noexcept(
204 std::is_nothrow_copy_assignable
<Value
>::value
) {
209 template <class... Args
>
210 Value
& emplace(Args
&&... args
) {
212 construct(std::forward
<Args
>(args
)...);
216 template <class U
, class... Args
>
217 typename
std::enable_if
<
218 std::is_constructible
<Value
, std::initializer_list
<U
>&, Args
&&...>::value
,
220 emplace(std::initializer_list
<U
> ilist
, Args
&&... args
) {
222 construct(ilist
, std::forward
<Args
>(args
)...);
226 void reset() noexcept
{
230 void clear() noexcept
{
234 void swap(Optional
& that
) noexcept(IsNothrowSwappable
<Value
>::value
) {
235 if (hasValue() && that
.hasValue()) {
237 swap(value(), that
.value());
238 } else if (hasValue()) {
239 that
.emplace(std::move(value()));
241 } else if (that
.hasValue()) {
242 emplace(std::move(that
.value()));
247 const Value
& value() const& {
249 return storage_
.value
;
254 return storage_
.value
;
259 return std::move(storage_
.value
);
262 const Value
&& value() const&& {
264 return std::move(storage_
.value
);
267 const Value
* get_pointer() const& {
268 return storage_
.hasValue
? &storage_
.value
: nullptr;
270 Value
* get_pointer() & {
271 return storage_
.hasValue
? &storage_
.value
: nullptr;
273 Value
* get_pointer() && = delete;
275 bool has_value() const noexcept
{
276 return storage_
.hasValue
;
279 bool hasValue() const noexcept
{
283 explicit operator bool() const noexcept
{
287 const Value
& operator*() const& {
290 Value
& operator*() & {
293 const Value
&& operator*() const&& {
294 return std::move(value());
296 Value
&& operator*() && {
297 return std::move(value());
300 const Value
* operator->() const {
303 Value
* operator->() {
307 // Return a copy of the value if set, or a given default if not.
309 Value
value_or(U
&& dflt
) const& {
310 if (storage_
.hasValue
) {
311 return storage_
.value
;
314 return std::forward
<U
>(dflt
);
318 Value
value_or(U
&& dflt
) && {
319 if (storage_
.hasValue
) {
320 return std::move(storage_
.value
);
323 return std::forward
<U
>(dflt
);
328 friend Optional
<_t
<std::decay
<T
>>> make_optional(T
&&);
329 template <class T
, class... Args
>
330 friend Optional
<T
> make_optional(Args
&&... args
);
331 template <class T
, class U
, class... As
>
332 friend Optional
<T
> make_optional(std::initializer_list
<U
>, As
&&...);
335 * Construct the optional in place, this is duplicated as a non-explicit
336 * constructor to allow returning values that are non-movable from
337 * make_optional using list initialization.
339 * Until C++17, at which point this will become unnecessary because of
340 * specified prvalue elision.
342 struct PrivateConstructor
{
343 explicit PrivateConstructor() = default;
345 template <typename
... Args
>
346 Optional(PrivateConstructor
, Args
&&... args
) noexcept(
347 std::is_constructible
<Value
, Args
&&...>::value
) {
348 construct(std::forward
<Args
>(args
)...);
351 void require_value() const {
352 if (!storage_
.hasValue
) {
353 throw OptionalEmptyException
{};
357 template <class... Args
>
358 void construct(Args
&&... args
) {
359 const void* ptr
= &storage_
.value
;
360 // For supporting const types.
361 new (const_cast<void*>(ptr
)) Value(std::forward
<Args
>(args
)...);
362 storage_
.hasValue
= true;
365 struct StorageTriviallyDestructible
{
372 StorageTriviallyDestructible()
373 : emptyState('\0'), hasValue
{false} {}
379 struct StorageNonTriviallyDestructible
{
386 StorageNonTriviallyDestructible() : hasValue
{false} {}
387 ~StorageNonTriviallyDestructible() {
399 using Storage
= typename
std::conditional
<
400 std::is_trivially_destructible
<Value
>::value
,
401 StorageTriviallyDestructible
,
402 StorageNonTriviallyDestructible
>::type
;
408 const T
* get_pointer(const Optional
<T
>& opt
) {
409 return opt
.get_pointer();
413 T
* get_pointer(Optional
<T
>& opt
) {
414 return opt
.get_pointer();
418 void swap(Optional
<T
>& a
, Optional
<T
>& b
) noexcept(noexcept(a
.swap(b
))) {
423 Optional
<_t
<std::decay
<T
>>> make_optional(T
&& v
) {
424 using PrivateConstructor
=
425 typename
folly::Optional
<_t
<std::decay
<T
>>>::PrivateConstructor
;
426 return {PrivateConstructor
{}, std::forward
<T
>(v
)};
429 template <class T
, class... Args
>
430 folly::Optional
<T
> make_optional(Args
&&... args
) {
431 using PrivateConstructor
= typename
folly::Optional
<T
>::PrivateConstructor
;
432 return {PrivateConstructor
{}, std::forward
<Args
>(args
)...};
435 template <class T
, class U
, class... Args
>
436 folly::Optional
<T
> make_optional(
437 std::initializer_list
<U
> il
,
439 using PrivateConstructor
= typename
folly::Optional
<T
>::PrivateConstructor
;
440 return {PrivateConstructor
{}, il
, std::forward
<Args
>(args
)...};
443 ///////////////////////////////////////////////////////////////////////////////
446 template <class U
, class V
>
447 bool operator==(const Optional
<U
>& a
, const V
& b
) {
448 return a
.hasValue() && a
.value() == b
;
451 template <class U
, class V
>
452 bool operator!=(const Optional
<U
>& a
, const V
& b
) {
456 template <class U
, class V
>
457 bool operator==(const U
& a
, const Optional
<V
>& b
) {
458 return b
.hasValue() && b
.value() == a
;
461 template <class U
, class V
>
462 bool operator!=(const U
& a
, const Optional
<V
>& b
) {
466 template <class U
, class V
>
467 bool operator==(const Optional
<U
>& a
, const Optional
<V
>& b
) {
468 if (a
.hasValue() != b
.hasValue()) {
472 return a
.value() == b
.value();
477 template <class U
, class V
>
478 bool operator!=(const Optional
<U
>& a
, const Optional
<V
>& b
) {
482 template <class U
, class V
>
483 bool operator<(const Optional
<U
>& a
, const Optional
<V
>& b
) {
484 if (a
.hasValue() != b
.hasValue()) {
485 return a
.hasValue() < b
.hasValue();
488 return a
.value() < b
.value();
493 template <class U
, class V
>
494 bool operator>(const Optional
<U
>& a
, const Optional
<V
>& b
) {
498 template <class U
, class V
>
499 bool operator<=(const Optional
<U
>& a
, const Optional
<V
>& b
) {
503 template <class U
, class V
>
504 bool operator>=(const Optional
<U
>& a
, const Optional
<V
>& b
) {
508 // Suppress comparability of Optional<T> with T, despite implicit conversion.
510 bool operator<(const Optional
<V
>&, const V
& other
) = delete;
512 bool operator<=(const Optional
<V
>&, const V
& other
) = delete;
514 bool operator>=(const Optional
<V
>&, const V
& other
) = delete;
516 bool operator>(const Optional
<V
>&, const V
& other
) = delete;
518 bool operator<(const V
& other
, const Optional
<V
>&) = delete;
520 bool operator<=(const V
& other
, const Optional
<V
>&) = delete;
522 bool operator>=(const V
& other
, const Optional
<V
>&) = delete;
524 bool operator>(const V
& other
, const Optional
<V
>&) = delete;
526 // Comparisons with none
528 bool operator==(const Optional
<V
>& a
, None
) noexcept
{
529 return !a
.hasValue();
532 bool operator==(None
, const Optional
<V
>& a
) noexcept
{
533 return !a
.hasValue();
536 bool operator<(const Optional
<V
>&, None
) noexcept
{
540 bool operator<(None
, const Optional
<V
>& a
) noexcept
{
544 bool operator>(const Optional
<V
>& a
, None
) noexcept
{
548 bool operator>(None
, const Optional
<V
>&) noexcept
{
552 bool operator<=(None
, const Optional
<V
>&) noexcept
{
556 bool operator<=(const Optional
<V
>& a
, None
) noexcept
{
557 return !a
.hasValue();
560 bool operator>=(const Optional
<V
>&, None
) noexcept
{
564 bool operator>=(None
, const Optional
<V
>& a
) noexcept
{
565 return !a
.hasValue();
568 ///////////////////////////////////////////////////////////////////////////////