///
// optional - An implementation of std::optional with extensions
// Written in 2017 by Sy Brand (@TartanLlama)
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to the
// public domain worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software. If not, see
// .
///
#pragma once
#include
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
# pragma GCC system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
# pragma clang system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
# pragma system_header
#endif // no system header
#include
#include
#include
#include
#define THRUST_OPTIONAL_VERSION_MAJOR 0
#define THRUST_OPTIONAL_VERSION_MINOR 2
#include
#include
#include
#include
#include
#if defined(_CCCL_COMPILER_MSVC) && _MSC_VER == 1900
# define THRUST_OPTIONAL_MSVC2015
#endif
#if _CCCL_STD_VER > 2011
# define THRUST_OPTIONAL_CPP14
#endif
// constexpr implies const in C++11, not C++14
#if (_CCCL_STD_VER == 2011 || defined(THRUST_OPTIONAL_MSVC2015) || defined(THRUST_OPTIONAL_GCC49))
/// \exclude
# define THRUST_OPTIONAL_CPP11_CONSTEXPR
#else
/// \exclude
# define THRUST_OPTIONAL_CPP11_CONSTEXPR constexpr
#endif
THRUST_NAMESPACE_BEGIN
#ifndef THRUST_MONOSTATE_INPLACE_MUTEX
# define THRUST_MONOSTATE_INPLACE_MUTEX
/// \brief Used to represent an optional with no data; essentially a bool
class monostate
{};
/// \brief A tag type to tell optional to construct its value in-place
struct in_place_t
{
explicit in_place_t() = default;
};
/// \brief A tag to tell optional to construct its value in-place
static constexpr in_place_t in_place{};
#endif
template
class optional;
/// \exclude
namespace detail
{
#ifndef THRUST_TRAITS_MUTEX
# define THRUST_TRAITS_MUTEX
// C++14-style aliases for brevity
template
using remove_const_t = typename std::remove_const::type;
template
using remove_reference_t = typename std::remove_reference::type;
template
using decay_t = typename std::decay::type;
template
using enable_if_t = typename std::enable_if::type;
template
using conditional_t = typename std::conditional::type;
// std::conjunction from C++17
template
struct conjunction : std::true_type
{};
template
struct conjunction : B
{};
template
struct conjunction : std::conditional, B>::type
{};
# if defined(_LIBCPP_VERSION) && _CCCL_STD_VER == 2011
# define THRUST_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND
# endif
// In C++11 mode, there's an issue in libc++'s std::mem_fn
// which results in a hard-error when using it in a noexcept expression
// in some cases. This is a check to workaround the common failing case.
# ifdef THRUST_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND
template
struct is_pointer_to_non_const_member_func : std::false_type
{};
template
struct is_pointer_to_non_const_member_func : std::true_type
{};
template
struct is_pointer_to_non_const_member_func : std::true_type
{};
template
struct is_pointer_to_non_const_member_func : std::true_type
{};
template
struct is_pointer_to_non_const_member_func : std::true_type
{};
template
struct is_pointer_to_non_const_member_func : std::true_type
{};
template
struct is_pointer_to_non_const_member_func : std::true_type
{};
template
struct is_const_or_const_ref : std::false_type
{};
template
struct is_const_or_const_ref : std::true_type
{};
template
struct is_const_or_const_ref : std::true_type
{};
# endif
// std::invoke from C++17
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
_CCCL_EXEC_CHECK_DISABLE
template <
typename Fn,
typename... Args,
# ifdef THRUST_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND
typename = enable_if_t::value && is_const_or_const_ref::value)>,
# endif
typename = enable_if_t>::value>,
int = 0>
_CCCL_HOST_DEVICE constexpr auto
invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward(args)...)))
THRUST_TRAILING_RETURN(decltype(std::mem_fn(f)(std::forward(args)...)))
{
return std::mem_fn(f)(std::forward(args)...);
}
_CCCL_EXEC_CHECK_DISABLE
template >::value>>
_CCCL_HOST_DEVICE constexpr auto
invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::forward(f)(std::forward(args)...)))
THRUST_TRAILING_RETURN(decltype(std::forward(f)(std::forward(args)...)))
{
return std::forward(f)(std::forward(args)...);
}
#endif
// std::void_t from C++17
template
struct voider
{
using type = void;
};
template
using void_t = typename voider::type;
// Trait for checking if a type is a thrust::optional
template
struct is_optional_impl : std::false_type
{};
template
struct is_optional_impl> : std::true_type
{};
template
using is_optional = is_optional_impl>;
// Change void to thrust::monostate
template
using fixup_void = conditional_t::value, monostate, U>;
template >
using get_map_return = optional>>;
// Check if invoking F for some Us returns void
template
struct returns_void_impl;
template
struct returns_void_impl>, U...> : std::is_void>
{};
template
using returns_void = returns_void_impl;
template
using enable_if_ret_void = enable_if_t::value>;
template
using disable_if_ret_void = enable_if_t::value>;
template
using enable_forward_value =
detail::enable_if_t::value && !std::is_same, in_place_t>::value
&& !std::is_same, detail::decay_t>::value>;
template
using enable_from_other = detail::enable_if_t<
std::is_constructible::value && !std::is_constructible&>::value
&& !std::is_constructible&&>::value && !std::is_constructible&>::value
&& !std::is_constructible&&>::value && !std::is_convertible&, T>::value
&& !std::is_convertible&&, T>::value && !std::is_convertible&, T>::value
&& !std::is_convertible&&, T>::value>;
template
using enable_assign_forward =
detail::enable_if_t, detail::decay_t>::value
&& !detail::conjunction, std::is_same>>::value
&& std::is_constructible::value && std::is_assignable::value>;
template
using enable_assign_from_other = detail::enable_if_t<
std::is_constructible::value && std::is_assignable::value
&& !std::is_constructible&>::value && !std::is_constructible&&>::value
&& !std::is_constructible&>::value && !std::is_constructible&&>::value
&& !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value
&& !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value
&& !std::is_assignable&>::value && !std::is_assignable&&>::value
&& !std::is_assignable&>::value && !std::is_assignable&&>::value>;
#if defined(_CCCL_COMPILER_MSVC)
// TODO make a version which works with MSVC
template
struct is_swappable : std::true_type
{};
template
struct is_nothrow_swappable : std::true_type
{};
#else
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
namespace swap_adl_tests
{
// if swap ADL finds this then it would call std::swap otherwise (same
// signature)
struct tag
{};
template
tag swap(T&, T&);
template
tag swap(T (&a)[N], T (&b)[N]);
// helper functions to test if an unqualified swap is possible, and if it
// becomes std::swap
template
std::false_type can_swap(...) noexcept(false);
template (), std::declval()))>
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), std::declval())));
template
std::false_type uses_std(...);
template
std::is_same(), std::declval())), tag> uses_std(int);
template
struct is_std_swap_noexcept
: std::integral_constant::value && std::is_nothrow_move_assignable::value>
{};
template
struct is_std_swap_noexcept : is_std_swap_noexcept
{};
template
struct is_adl_swap_noexcept : std::integral_constant(0))>
{};
} // namespace swap_adl_tests
template
struct is_swappable
: std::integral_constant(0))::value
&& (!decltype(detail::swap_adl_tests::uses_std(0))::value
|| (std::is_move_assignable::value && std::is_move_constructible::value))>
{};
template
struct is_swappable
: std::integral_constant<
bool,
decltype(detail::swap_adl_tests::can_swap(0))::value
&& (!decltype(detail::swap_adl_tests::uses_std(0))::value || is_swappable::value)>
{};
template
struct is_nothrow_swappable
: std::integral_constant::value
&& ((decltype(detail::swap_adl_tests::uses_std(0))::value
&& detail::swap_adl_tests::is_std_swap_noexcept::value)
|| (!decltype(detail::swap_adl_tests::uses_std(0))::value
&& detail::swap_adl_tests::is_adl_swap_noexcept::value))>
{};
#endif
// The storage base manages the actual storage, and correctly propagates
// trivial destruction from T. This case is for when T is not trivially
// destructible.
template ::value>
struct optional_storage_base
{
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR optional_storage_base() noexcept
: m_dummy()
, m_has_value(false)
{}
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR optional_storage_base(in_place_t, U&&... u)
: m_value(std::forward(u)...)
, m_has_value(true)
{}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE ~optional_storage_base()
{
if (m_has_value)
{
m_value.~T();
m_has_value = false;
}
}
struct dummy
{};
union
{
dummy m_dummy;
T m_value;
};
bool m_has_value;
};
// This case is for when T is trivially destructible.
template
struct optional_storage_base
{
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR optional_storage_base() noexcept
: m_dummy()
, m_has_value(false)
{}
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR optional_storage_base(in_place_t, U&&... u)
: m_value(std::forward(u)...)
, m_has_value(true)
{}
// No destructor, so this class is trivially destructible
struct dummy
{};
union
{
dummy m_dummy;
T m_value;
};
bool m_has_value = false;
};
// This base class provides some handy member functions which can be used in
// further derived classes
template
struct optional_operations_base : optional_storage_base
{
using optional_storage_base::optional_storage_base;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE void hard_reset() noexcept
{
get().~T();
this->m_has_value = false;
}
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE void construct(Args&&... args) noexcept
{
new (thrust::addressof(this->m_value)) T(std::forward(args)...);
this->m_has_value = true;
}
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE void assign(Opt&& rhs)
{
if (this->has_value())
{
if (rhs.has_value())
{
this->m_value = std::forward(rhs).get();
}
else
{
this->m_value.~T();
this->m_has_value = false;
}
}
if (rhs.has_value())
{
construct(std::forward(rhs).get());
}
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE bool has_value() const
{
return this->m_has_value;
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR T& get() &
{
return this->m_value;
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR const T& get() const&
{
return this->m_value;
}
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR T&& get() &&
{
return std::move(this->m_value);
}
#ifndef THRUST_OPTIONAL_NO_CONSTRR
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE constexpr const T&& get() const&&
{
return std::move(this->m_value);
}
#endif
};
// This class manages conditionally having a trivial copy constructor
// This specialization is for when T is trivially copy constructible
template ::value>
struct optional_copy_base : optional_operations_base
{
using optional_operations_base::optional_operations_base;
};
// This specialization is for when T is not trivially copy constructible
template
struct optional_copy_base : optional_operations_base
{
using optional_operations_base::optional_operations_base;
_CCCL_EXEC_CHECK_DISABLE
optional_copy_base() = default;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE optional_copy_base(const optional_copy_base& rhs)
{
if (rhs.has_value())
{
this->construct(rhs.get());
}
else
{
this->m_has_value = false;
}
}
_CCCL_EXEC_CHECK_DISABLE
optional_copy_base(optional_copy_base&& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_copy_base& operator=(const optional_copy_base& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_copy_base& operator=(optional_copy_base&& rhs) = default;
};
template ::value>
struct optional_move_base : optional_copy_base
{
using optional_copy_base::optional_copy_base;
};
template
struct optional_move_base : optional_copy_base
{
using optional_copy_base::optional_copy_base;
_CCCL_EXEC_CHECK_DISABLE
optional_move_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_move_base(const optional_move_base& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE optional_move_base(optional_move_base&& rhs) noexcept(std::is_nothrow_move_constructible::value)
{
if (rhs.has_value())
{
this->construct(std::move(rhs.get()));
}
else
{
this->m_has_value = false;
}
}
_CCCL_EXEC_CHECK_DISABLE
optional_move_base& operator=(const optional_move_base& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_move_base& operator=(optional_move_base&& rhs) = default;
};
// This class manages conditionally having a trivial copy assignment operator
template ::value
&& ::cuda::std::is_trivially_copy_constructible::value
&& ::cuda::std::is_trivially_destructible::value>
struct optional_copy_assign_base : optional_move_base
{
using optional_move_base::optional_move_base;
};
template
struct optional_copy_assign_base : optional_move_base
{
using optional_move_base::optional_move_base;
_CCCL_EXEC_CHECK_DISABLE
optional_copy_assign_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_copy_assign_base(const optional_copy_assign_base& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_copy_assign_base(optional_copy_assign_base&& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE optional_copy_assign_base& operator=(const optional_copy_assign_base& rhs)
{
this->assign(rhs);
return *this;
}
_CCCL_EXEC_CHECK_DISABLE
optional_copy_assign_base& operator=(optional_copy_assign_base&& rhs) = default;
};
template ::value
&& ::cuda::std::is_trivially_move_constructible::value
&& ::cuda::std::is_trivially_move_assignable::value>
struct optional_move_assign_base : optional_copy_assign_base
{
using optional_copy_assign_base::optional_copy_assign_base;
};
template
struct optional_move_assign_base : optional_copy_assign_base
{
using optional_copy_assign_base::optional_copy_assign_base;
_CCCL_EXEC_CHECK_DISABLE
optional_move_assign_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_move_assign_base(const optional_move_assign_base& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_move_assign_base(optional_move_assign_base&& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_move_assign_base& operator=(const optional_move_assign_base& rhs) = default;
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE optional_move_assign_base& operator=(optional_move_assign_base&& rhs) noexcept(
std::is_nothrow_move_constructible::value && std::is_nothrow_move_assignable::value)
{
this->assign(std::move(rhs));
return *this;
}
};
// optional_delete_ctor_base will conditionally delete copy and move
// constructors depending on whether T is copy/move constructible
template ::value,
bool EnableMove = std::is_move_constructible::value>
struct optional_delete_ctor_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(const optional_delete_ctor_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
};
template
struct optional_delete_ctor_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(const optional_delete_ctor_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
};
template
struct optional_delete_ctor_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(const optional_delete_ctor_base&) = delete;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
};
template
struct optional_delete_ctor_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(const optional_delete_ctor_base&) = delete;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
};
// optional_delete_assign_base will conditionally delete copy and move
// constructors depending on whether T is copy/move constructible + assignable
template ::value && std::is_copy_assignable::value),
bool EnableMove = (std::is_move_constructible::value && std::is_move_assignable::value)>
struct optional_delete_assign_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(const optional_delete_assign_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default;
};
template
struct optional_delete_assign_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(const optional_delete_assign_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete;
};
template
struct optional_delete_assign_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(const optional_delete_assign_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default;
};
template
struct optional_delete_assign_base
{
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base() = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(const optional_delete_assign_base&) = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete;
_CCCL_EXEC_CHECK_DISABLE
optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete;
};
} // namespace detail
/// \brief A tag type to represent an empty optional
struct nullopt_t
{
struct do_not_use
{};
_CCCL_HOST_DEVICE constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {}
};
/// \brief Represents an empty optional
/// \synopsis static constexpr nullopt_t nullopt;
///
/// *Examples*:
/// ```
/// thrust::optional a = thrust::nullopt;
/// void foo (thrust::optional);
/// foo(thrust::nullopt); //pass an empty optional
/// ```
#ifdef __CUDA_ARCH__
__device__ static _LIBCUDACXX_CONSTEXPR_GLOBAL
#else
static constexpr
#endif // __CUDA_ARCH__
nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}};
class bad_optional_access : public std::exception
{
public:
bad_optional_access() = default;
_CCCL_HOST const char* what() const noexcept
{
return "Optional has no value";
}
};
/// An optional object is an object that contains the storage for another
/// object and manages the lifetime of this contained object, if any. The
/// contained object may be initialized after the optional object has been
/// initialized, and may be destroyed before the optional object has been
/// destroyed. The initialization state of the contained object is tracked by
/// the optional object.
template
class optional
: private detail::optional_move_assign_base
, private detail::optional_delete_ctor_base
, private detail::optional_delete_assign_base
{
using base = detail::optional_move_assign_base;
static_assert(!std::is_same::value, "instantiation of optional with in_place_t is ill-formed");
static_assert(!std::is_same, nullopt_t>::value,
"instantiation of optional with nullopt_t is ill-formed");
public:
// The different versions for C++14 and 11 are needed because deduced return
// types are not SFINAE-safe. This provides better support for things like
// generic lambdas. C.f.
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0
#if defined(THRUST_OPTIONAL_CPP14) && !defined(THRUST_OPTIONAL_GCC49) && !defined(THRUST_OPTIONAL_GCC54) \
&& !defined(THRUST_OPTIONAL_GCC55)
/// \group and_then
/// Carries out some operation which returns an optional on the stored
/// object if there is one. \requires `std::invoke(std::forward(f),
/// value())` returns a `std::optional` for some `U`. \return Let `U` be
/// the result of `std::invoke(std::forward(f), value())`. Returns a
/// `std::optional`. The return value is empty if `*this` is empty,
/// otherwise the return value of `std::invoke(std::forward(f), value())`
/// is returned.
/// \group and_then
/// \synopsis template \nconstexpr auto and_then(F &&f) &;
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR auto and_then(F&& f) &
{
using result = detail::invoke_result_t;
static_assert(detail::is_optional::value, "F must return an optional");
return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt);
}
/// \group and_then
/// \synopsis template \nconstexpr auto and_then(F &&f) &&;
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE THRUST_OPTIONAL_CPP11_CONSTEXPR auto and_then(F&& f) &&
{
using result = detail::invoke_result_t;
static_assert(detail::is_optional::value, "F must return an optional");
return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt);
}
/// \group and_then
/// \synopsis template \nconstexpr auto and_then(F &&f) const &;
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE constexpr auto and_then(F&& f) const&
{
using result = detail::invoke_result_t;
static_assert(detail::is_optional::value, "F must return an optional");
return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt);
}
# ifndef THRUST_OPTIONAL_NO_CONSTRR
/// \group and_then
/// \synopsis template \nconstexpr auto and_then(F &&f) const &&;
_CCCL_EXEC_CHECK_DISABLE
template
_CCCL_HOST_DEVICE constexpr auto and_then(F&& f) const&&
{
using result = detail::invoke_result_t;
static_assert(detail::is_optional::value, "F must return an optional");
return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt);
}
# endif
#else
/// \group and_then
/// Carries out some operation which returns an optional on the stored
/// object if there is one. \requires `std::invoke(std::forward(f),
/// value())` returns a `std::optional