/// // 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 #include #if THRUST_CPP_DIALECT >= 2011 #include #include #define THRUST_OPTIONAL_VERSION_MAJOR 0 #define THRUST_OPTIONAL_VERSION_MINOR 2 #include #include #include #include #include #if (THRUST_HOST_COMPILER == THRUST_HOST_COMPILER_MSVC && _MSC_VER == 1900) #define THRUST_OPTIONAL_MSVC2015 #endif #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) #define THRUST_OPTIONAL_GCC49 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ !defined(__clang__)) #define THRUST_OPTIONAL_GCC54 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ !defined(__clang__)) #define THRUST_OPTIONAL_GCC55 #endif #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) // GCC < 5 doesn't support overloading on const&& for member functions #define THRUST_OPTIONAL_NO_CONSTRR // GCC < 5 doesn't support some standard C++11 type traits #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::has_trivial_copy_constructor::value #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign::value // GCC < 5 doesn't provide a way to emulate std::is_trivially_move_*, // so don't enable any optimizations that rely on them: #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE(T) false #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_ASSIGNABLE(T) false // This one will be different for GCC 5.7 if it's ever supported #define THRUST_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector // for non-copyable types #elif (defined(__GNUC__) && __GNUC__ < 8 && \ !defined(__clang__)) #ifndef THRUST_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX #define THRUST_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX THRUST_NAMESPACE_BEGIN namespace detail { template struct is_trivially_copy_constructible : std::is_trivially_copy_constructible{}; #ifdef _GLIBCXX_VECTOR template struct is_trivially_copy_constructible> : std::is_trivially_copy_constructible{}; #endif } THRUST_NAMESPACE_END #endif #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ thrust::detail::is_trivially_copy_constructible::value #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::is_trivially_copy_assignable::value #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE(T) \ std::is_trivially_move_constructible::value #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_ASSIGNABLE(T) \ std::is_trivially_move_assignable::value #define THRUST_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value #else // To support clang + old libstdc++ without type traits, check for equivalent // clang built-ins and use them if present. See note above // is_trivially_copyable_impl in // thrust/type_traits/is_trivially_relocatable.h for more details. #ifndef __has_feature #define __has_feature(x) 0 #endif #if defined(__GLIBCXX__) && __has_feature(is_trivially_constructible) #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ __is_trivially_constructible(T, T const&) #else #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::is_trivially_copy_constructible::value #endif #if defined(__GLIBCXX__) && __has_feature(is_trivially_assignable) #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ __is_trivially_assignable(T, T const&) #else #define THRUST_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::is_trivially_copy_assignable::value #endif #if defined(__GLIBCXX__) && __has_feature(is_trivially_constructible) #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE(T) \ __is_trivially_constructible(T, T&&) #else #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE(T) \ std::is_trivially_move_constructible::value #endif #if defined(__GLIBCXX__) && __has_feature(is_trivially_assignable) #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_ASSIGNABLE(T) \ __is_trivially_assignable(T, T&&) #else #define THRUST_OPTIONAL_IS_TRIVIALLY_MOVE_ASSIGNABLE(T) \ std::is_trivially_move_assignable::value #endif #if defined(__GLIBCXX__) && __has_feature(is_trivially_destructible) #define THRUST_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ __is_trivially_destructible(T) #else #define THRUST_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) \ std::is_trivially_destructible::value #endif #endif #if THRUST_CPP_DIALECT > 2011 #define THRUST_OPTIONAL_CPP14 #endif // constexpr implies const in C++11, not C++14 #if (THRUST_CPP_DIALECT == 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) && THRUST_CPP_DIALECT == 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 __thrust_exec_check_disable__ template ::value && is_const_or_const_ref::value)>, #endif typename = enable_if_t>::value>, int = 0> __host__ __device__ constexpr auto invoke(Fn &&f, Args &&... args) noexcept( noexcept(std::mem_fn(f)(std::forward(args)...))) -> decltype(std::mem_fn(f)(std::forward(args)...)) { return std::mem_fn(f)(std::forward(args)...); } __thrust_exec_check_disable__ template >::value>> __host__ __device__ constexpr auto invoke(Fn &&f, Args &&... args) noexcept( noexcept(std::forward(f)(std::forward(args)...))) -> decltype(std::forward(f)(std::forward(args)...)) { return std::forward(f)(std::forward(args)...); } // std::invoke_result from C++17 template struct invoke_result_impl; template struct invoke_result_impl< F, decltype(detail::invoke(std::declval(), std::declval()...), void()), Us...> { using type = decltype(detail::invoke(std::declval(), std::declval()...)); }; template using invoke_result = invoke_result_impl; template using invoke_result_t = typename invoke_result::type; #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< !std::is_same, 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 THRUST_HOST_COMPILER == THRUST_HOST_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< bool, decltype(detail::swap_adl_tests::can_swap(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< bool, is_swappable::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 { __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) : m_value(std::forward(u)...), m_has_value(true) {} __thrust_exec_check_disable__ __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 { __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} __thrust_exec_check_disable__ template __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; __thrust_exec_check_disable__ __host__ __device__ void hard_reset() noexcept { get().~T(); this->m_has_value = false; } __thrust_exec_check_disable__ template __host__ __device__ void construct(Args &&... args) noexcept { new (thrust::addressof(this->m_value)) T(std::forward(args)...); this->m_has_value = true; } __thrust_exec_check_disable__ template __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()); } } __thrust_exec_check_disable__ __host__ __device__ bool has_value() const { return this->m_has_value; } __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &get() & { return this->m_value; } __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR const T &get() const & { return this->m_value; } __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &&get() && { return std::move(this->m_value); } #ifndef THRUST_OPTIONAL_NO_CONSTRR __thrust_exec_check_disable__ __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 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; __thrust_exec_check_disable__ optional_copy_base() = default; __thrust_exec_check_disable__ __host__ __device__ optional_copy_base(const optional_copy_base &rhs) { if (rhs.has_value()) { this->construct(rhs.get()); } else { this->m_has_value = false; } } __thrust_exec_check_disable__ optional_copy_base(optional_copy_base &&rhs) = default; __thrust_exec_check_disable__ optional_copy_base &operator=(const optional_copy_base &rhs) = default; __thrust_exec_check_disable__ optional_copy_base &operator=(optional_copy_base &&rhs) = default; }; template 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; __thrust_exec_check_disable__ optional_move_base() = default; __thrust_exec_check_disable__ optional_move_base(const optional_move_base &rhs) = default; __thrust_exec_check_disable__ __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; } } __thrust_exec_check_disable__ optional_move_base &operator=(const optional_move_base &rhs) = default; __thrust_exec_check_disable__ optional_move_base &operator=(optional_move_base &&rhs) = default; }; // This class manages conditionally having a trivial copy assignment operator template 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; __thrust_exec_check_disable__ optional_copy_assign_base() = default; __thrust_exec_check_disable__ optional_copy_assign_base(const optional_copy_assign_base &rhs) = default; __thrust_exec_check_disable__ optional_copy_assign_base(optional_copy_assign_base &&rhs) = default; __thrust_exec_check_disable__ __host__ __device__ optional_copy_assign_base &operator=(const optional_copy_assign_base &rhs) { this->assign(rhs); return *this; } __thrust_exec_check_disable__ optional_copy_assign_base & operator=(optional_copy_assign_base &&rhs) = default; }; template 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; __thrust_exec_check_disable__ optional_move_assign_base() = default; __thrust_exec_check_disable__ optional_move_assign_base(const optional_move_assign_base &rhs) = default; __thrust_exec_check_disable__ optional_move_assign_base(optional_move_assign_base &&rhs) = default; __thrust_exec_check_disable__ optional_move_assign_base & operator=(const optional_move_assign_base &rhs) = default; __thrust_exec_check_disable__ __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 { __thrust_exec_check_disable__ optional_delete_ctor_base() = default; __thrust_exec_check_disable__ optional_delete_ctor_base(const optional_delete_ctor_base &) = default; __thrust_exec_check_disable__ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; __thrust_exec_check_disable__ optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; __thrust_exec_check_disable__ optional_delete_ctor_base & operator=(optional_delete_ctor_base &&) noexcept = default; }; template struct optional_delete_ctor_base { __thrust_exec_check_disable__ optional_delete_ctor_base() = default; __thrust_exec_check_disable__ optional_delete_ctor_base(const optional_delete_ctor_base &) = default; __thrust_exec_check_disable__ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; __thrust_exec_check_disable__ optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; __thrust_exec_check_disable__ optional_delete_ctor_base & operator=(optional_delete_ctor_base &&) noexcept = default; }; template struct optional_delete_ctor_base { __thrust_exec_check_disable__ optional_delete_ctor_base() = default; __thrust_exec_check_disable__ optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; __thrust_exec_check_disable__ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; __thrust_exec_check_disable__ optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; __thrust_exec_check_disable__ optional_delete_ctor_base & operator=(optional_delete_ctor_base &&) noexcept = default; }; template struct optional_delete_ctor_base { __thrust_exec_check_disable__ optional_delete_ctor_base() = default; __thrust_exec_check_disable__ optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; __thrust_exec_check_disable__ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; __thrust_exec_check_disable__ optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; __thrust_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 { __thrust_exec_check_disable__ optional_delete_assign_base() = default; __thrust_exec_check_disable__ optional_delete_assign_base(const optional_delete_assign_base &) = default; __thrust_exec_check_disable__ optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; __thrust_exec_check_disable__ optional_delete_assign_base & operator=(const optional_delete_assign_base &) = default; __thrust_exec_check_disable__ optional_delete_assign_base & operator=(optional_delete_assign_base &&) noexcept = default; }; template struct optional_delete_assign_base { __thrust_exec_check_disable__ optional_delete_assign_base() = default; __thrust_exec_check_disable__ optional_delete_assign_base(const optional_delete_assign_base &) = default; __thrust_exec_check_disable__ optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; __thrust_exec_check_disable__ optional_delete_assign_base & operator=(const optional_delete_assign_base &) = default; __thrust_exec_check_disable__ optional_delete_assign_base & operator=(optional_delete_assign_base &&) noexcept = delete; }; template struct optional_delete_assign_base { __thrust_exec_check_disable__ optional_delete_assign_base() = default; __thrust_exec_check_disable__ optional_delete_assign_base(const optional_delete_assign_base &) = default; __thrust_exec_check_disable__ optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; __thrust_exec_check_disable__ optional_delete_assign_base & operator=(const optional_delete_assign_base &) = delete; __thrust_exec_check_disable__ optional_delete_assign_base & operator=(optional_delete_assign_base &&) noexcept = default; }; template struct optional_delete_assign_base { __thrust_exec_check_disable__ optional_delete_assign_base() = default; __thrust_exec_check_disable__ optional_delete_assign_base(const optional_delete_assign_base &) = default; __thrust_exec_check_disable__ optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; __thrust_exec_check_disable__ optional_delete_assign_base & operator=(const optional_delete_assign_base &) = delete; __thrust_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 {}; __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 /// ``` static constexpr 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; __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`. \returns 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) &; __thrust_exec_check_disable__ template __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) &&; __thrust_exec_check_disable__ template __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 &; __thrust_exec_check_disable__ template __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 &&; __thrust_exec_check_disable__ template __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` for some `U`. /// \returns 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) &; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR detail::invoke_result_t 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) &&; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR detail::invoke_result_t 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 &; __thrust_exec_check_disable__ template __host__ __device__ constexpr detail::invoke_result_t 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 &&; __thrust_exec_check_disable__ template __host__ __device__ constexpr detail::invoke_result_t 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 #endif #if defined(THRUST_OPTIONAL_CPP14) && !defined(THRUST_OPTIONAL_GCC49) && \ !defined(THRUST_OPTIONAL_GCC54) && !defined(THRUST_OPTIONAL_GCC55) /// \brief Carries out some operation on the stored object if there is one. /// \returns 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 an `optional` is constructed from the /// return value of `std::invoke(std::forward(f), value())` and is /// returned. /// /// \group map /// \synopsis template constexpr auto map(F &&f) &; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR auto map(F &&f) & { return optional_map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) &&; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR auto map(F &&f) && { return optional_map_impl(std::move(*this), std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) const&; __thrust_exec_check_disable__ template __host__ __device__ constexpr auto map(F &&f) const & { return optional_map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) const&&; __thrust_exec_check_disable__ template __host__ __device__ constexpr auto map(F &&f) const && { return optional_map_impl(std::move(*this), std::forward(f)); } #else /// \brief Carries out some operation on the stored object if there is one. /// \returns 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 an `optional` is constructed from the /// return value of `std::invoke(std::forward(f), value())` and is /// returned. /// /// \group map /// \synopsis template auto map(F &&f) &; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) & { return optional_map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template auto map(F &&f) &&; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) && { return optional_map_impl(std::move(*this), std::forward(f)); } /// \group map /// \synopsis template auto map(F &&f) const&; __thrust_exec_check_disable__ template __host__ __device__ constexpr decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) const & { return optional_map_impl(*this, std::forward(f)); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group map /// \synopsis template auto map(F &&f) const&&; __thrust_exec_check_disable__ template __host__ __device__ constexpr decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) const && { return optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif /// \brief Calls `f` if the optional is empty /// \requires `std::invoke_result_t` must be void or convertible to /// `optional`. /// \effects If `*this` has a value, returns `*this`. /// Otherwise, if `f` returns `void`, calls `std::forward(f)` and returns /// `std::nullopt`. Otherwise, returns `std::forward(f)()`. /// /// \group or_else /// \synopsis template optional or_else (F &&f) &; __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) & { if (has_value()) return *this; std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) & { return has_value() ? *this : std::forward(f)(); } /// \group or_else /// \synopsis template optional or_else (F &&f) &&; __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) && { return has_value() ? std::move(*this) : std::forward(f)(); } /// \group or_else /// \synopsis template optional or_else (F &&f) const &; __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) const & { if (has_value()) return *this; std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) const & { return has_value() ? *this : std::forward(f)(); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) const && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) const && { return has_value() ? std::move(*this) : std::forward(f)(); } #endif /// \brief Maps the stored value with `f` if there is one, otherwise returns /// `u`. /// /// \details If there is a value stored, then `f` is called with `**this` /// and the value is returned. Otherwise `u` is returned. /// /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } #endif /// \brief Maps the stored value with `f` if there is one, otherwise calls /// `u` and returns the result. /// /// \details If there is a value stored, then `f` is /// called with `**this` and the value is returned. Otherwise /// `std::forward(u)()` is returned. /// /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) &; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) /// &&; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) /// const &; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) /// const &&; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } #endif /// \returns `u` if `*this` has a value, otherwise an empty optional. __thrust_exec_check_disable__ template __host__ __device__ constexpr optional::type> conjunction(U &&u) const { using result = optional>; return has_value() ? result{u} : result{nullopt}; } /// \returns `rhs` if `*this` is empty, otherwise the current value. /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(const optional &rhs) & { return has_value() ? *this : rhs; } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(const optional &rhs) const & { return has_value() ? *this : rhs; } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(const optional &rhs) && { return has_value() ? std::move(*this) : rhs; } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(const optional &rhs) const && { return has_value() ? std::move(*this) : rhs; } #endif /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(optional &&rhs) & { return has_value() ? *this : std::move(rhs); } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(optional &&rhs) const & { return has_value() ? *this : std::move(rhs); } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(optional &&rhs) && { return has_value() ? std::move(*this) : std::move(rhs); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(optional &&rhs) const && { return has_value() ? std::move(*this) : std::move(rhs); } #endif /// Takes the value out of the optional, leaving it empty /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() & { optional ret = *this; reset(); return ret; } /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() const & { optional ret = *this; reset(); return ret; } /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() && { optional ret = std::move(*this); reset(); return ret; } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() const && { optional ret = std::move(*this); reset(); return ret; } #endif using value_type = T; /// Constructs an optional that does not contain a value. /// \group ctor_empty __thrust_exec_check_disable__ constexpr optional() noexcept = default; /// \group ctor_empty __thrust_exec_check_disable__ __host__ __device__ constexpr optional(nullopt_t) noexcept {} /// Copy constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. __thrust_exec_check_disable__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional(const optional &rhs) = default; /// Move constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. __thrust_exec_check_disable__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional(optional &&rhs) = default; /// Constructs the stored value in-place using the given arguments. /// \group in_place /// \synopsis template constexpr explicit optional(in_place_t, Args&&... args); __thrust_exec_check_disable__ template __host__ __device__ constexpr explicit optional( detail::enable_if_t::value, in_place_t>, Args &&... args) : base(in_place, std::forward(args)...) {} /// \group in_place /// \synopsis template \nconstexpr explicit optional(in_place_t, std::initializer_list&, Args&&... args); __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR explicit optional( detail::enable_if_t &, Args &&...>::value, in_place_t>, std::initializer_list il, Args &&... args) { this->construct(il, std::forward(args)...); } /// Constructs the stored value with `u`. /// \synopsis template constexpr optional(U &&u); __thrust_exec_check_disable__ template < class U = T, detail::enable_if_t::value> * = nullptr, detail::enable_forward_value * = nullptr> __host__ __device__ constexpr optional(U &&u) : base(in_place, std::forward(u)) {} /// \exclude __thrust_exec_check_disable__ template < class U = T, detail::enable_if_t::value> * = nullptr, detail::enable_forward_value * = nullptr> __host__ __device__ constexpr explicit optional(U &&u) : base(in_place, std::forward(u)) {} /// Converting copy constructor. /// \synopsis template optional(const optional &rhs); __thrust_exec_check_disable__ template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> __host__ __device__ optional(const optional &rhs) { this->construct(*rhs); } /// \exclude __thrust_exec_check_disable__ template * = nullptr, detail::enable_if_t::value> * = nullptr> __host__ __device__ explicit optional(const optional &rhs) { this->construct(*rhs); } /// Converting move constructor. /// \synopsis template optional(optional &&rhs); __thrust_exec_check_disable__ template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> __host__ __device__ optional(optional &&rhs) { this->construct(std::move(*rhs)); } /// \exclude __thrust_exec_check_disable__ template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> __host__ __device__ explicit optional(optional &&rhs) { this->construct(std::move(*rhs)); } /// Destroys the stored value if there is one. __thrust_exec_check_disable__ ~optional() = default; /// Assignment to empty. /// /// Destroys the current value if there is one. __thrust_exec_check_disable__ __host__ __device__ optional &operator=(nullopt_t) noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } return *this; } /// Copy assignment. /// /// Copies the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. __thrust_exec_check_disable__ optional &operator=(const optional &rhs) = default; /// Move assignment. /// /// Moves the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. __thrust_exec_check_disable__ optional &operator=(optional &&rhs) = default; /// Assigns the stored value from `u`, destroying the old value if there was /// one. /// \synopsis optional &operator=(U &&u); __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional &operator=(U &&u) { if (has_value()) { this->m_value = std::forward(u); } else { this->construct(std::forward(u)); } return *this; } /// Converting copy assignment operator. /// /// Copies the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. /// \synopsis optional &operator=(const optional & rhs); __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional &operator=(const optional &rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = *rhs; } else { this->hard_reset(); } } if (rhs.has_value()) { this->construct(*rhs); } return *this; } // TODO check exception guarantee /// Converting move assignment operator. /// /// Moves the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. /// \synopsis optional &operator=(optional && rhs); __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional &operator=(optional &&rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = std::move(*rhs); } else { this->hard_reset(); } } if (rhs.has_value()) { this->construct(std::move(*rhs)); } return *this; } /// Constructs the value in-place, destroying the current one if there is /// one. /// \group emplace __thrust_exec_check_disable__ template __host__ __device__ T &emplace(Args &&... args) { static_assert(std::is_constructible::value, "T must be constructible with Args"); *this = nullopt; this->construct(std::forward(args)...); return value(); } /// \group emplace /// \synopsis template \nT& emplace(std::initializer_list il, Args &&... args); __thrust_exec_check_disable__ template __host__ __device__ detail::enable_if_t< std::is_constructible &, Args &&...>::value, T &> emplace(std::initializer_list il, Args &&... args) { *this = nullopt; this->construct(il, std::forward(args)...); return value(); } /// Swaps this optional with the other. /// /// If neither optionals have a value, nothing happens. /// If both have a value, the values are swapped. /// If one has a value, it is moved to the other and the movee is left /// valueless. __thrust_exec_check_disable__ __host__ __device__ void swap(optional &rhs) noexcept(std::is_nothrow_move_constructible::value &&detail::is_nothrow_swappable::value) { if (has_value()) { if (rhs.has_value()) { using thrust::swap; swap(**this, *rhs); } else { new (addressof(rhs.m_value)) T(std::move(this->m_value)); this->m_value.T::~T(); } } else if (rhs.has_value()) { new (addressof(this->m_value)) T(std::move(rhs.m_value)); rhs.m_value.T::~T(); } } /// \returns a pointer to the stored value /// \requires a value is stored /// \group pointer /// \synopsis constexpr const T *operator->() const; __thrust_exec_check_disable__ __host__ __device__ constexpr const T *operator->() const { return addressof(this->m_value); } /// \group pointer /// \synopsis constexpr T *operator->(); __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T *operator->() { return addressof(this->m_value); } /// \returns the stored value /// \requires a value is stored /// \group deref /// \synopsis constexpr T &operator*(); __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &operator*() & { return this->m_value; } /// \group deref /// \synopsis constexpr const T &operator*() const; __thrust_exec_check_disable__ __host__ __device__ constexpr const T &operator*() const & { return this->m_value; } /// \exclude __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &&operator*() && { return std::move(this->m_value); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \exclude __thrust_exec_check_disable__ __host__ __device__ constexpr const T &&operator*() const && { return std::move(this->m_value); } #endif /// \returns whether or not the optional has a value /// \group has_value __thrust_exec_check_disable__ __host__ __device__ constexpr bool has_value() const noexcept { return this->m_has_value; } /// \group has_value __thrust_exec_check_disable__ __host__ __device__ constexpr explicit operator bool() const noexcept { return this->m_has_value; } /// \returns the contained value if there is one, otherwise throws /// [bad_optional_access] /// \group value /// \synopsis constexpr T &value(); __host__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &value() & { if (has_value()) return this->m_value; throw bad_optional_access(); } /// \group value /// \synopsis constexpr const T &value() const; __host__ THRUST_OPTIONAL_CPP11_CONSTEXPR const T &value() const & { if (has_value()) return this->m_value; throw bad_optional_access(); } /// \exclude __host__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &&value() && { if (has_value()) return std::move(this->m_value); throw bad_optional_access(); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \exclude __host__ THRUST_OPTIONAL_CPP11_CONSTEXPR const T &&value() const && { if (has_value()) return std::move(this->m_value); throw bad_optional_access(); } #endif /// \returns the stored value if there is one, otherwise returns `u` /// \group value_or __thrust_exec_check_disable__ template __host__ __device__ constexpr T value_or(U &&u) const & { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } /// \group value_or __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T value_or(U &&u) && { static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } /// Destroys the stored value if one exists, making the optional empty __thrust_exec_check_disable__ __host__ __device__ void reset() noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } } }; /// \group relop /// \brief Compares two optional objects /// \details If both optionals contain a value, they are compared with `T`s /// relational operators. Otherwise `lhs` and `rhs` are equal only if they are /// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` /// is not. __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator==(const optional &lhs, const optional &rhs) { return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); } /// \group relop __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator!=(const optional &lhs, const optional &rhs) { return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); } /// \group relop __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<(const optional &lhs, const optional &rhs) { return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); } /// \group relop __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>(const optional &lhs, const optional &rhs) { return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); } /// \group relop __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<=(const optional &lhs, const optional &rhs) { return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); } /// \group relop __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>=(const optional &lhs, const optional &rhs) { return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); } /// \group relop_nullopt /// \brief Compares an optional to a `nullopt` /// \details Equivalent to comparing the optional to an empty optional __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept { return !lhs.has_value(); } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept { return !rhs.has_value(); } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept { return lhs.has_value(); } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept { return rhs.has_value(); } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<(const optional &, nullopt_t) noexcept { return false; } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept { return rhs.has_value(); } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept { return !lhs.has_value(); } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<=(nullopt_t, const optional &) noexcept { return true; } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept { return lhs.has_value(); } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>(nullopt_t, const optional &) noexcept { return false; } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>=(const optional &, nullopt_t) noexcept { return true; } /// \group relop_nullopt __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept { return !rhs.has_value(); } /// \group relop_t /// \brief Compares the optional with a value. /// \details If the optional has a value, it is compared with the other value /// using `T`s relational operators. Otherwise, the optional is considered /// less than the value. __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator==(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs == rhs : false; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator==(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs == *rhs : false; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator!=(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs != rhs : true; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator!=(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs != *rhs : true; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs < rhs : true; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs < *rhs : false; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<=(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs <= rhs : true; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator<=(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs <= *rhs : false; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs > rhs : false; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs > *rhs : true; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>=(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs >= rhs : false; } /// \group relop_t __thrust_exec_check_disable__ template __host__ __device__ inline constexpr bool operator>=(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs >= *rhs : true; } /// \synopsis template \nvoid swap(optional &lhs, optional &rhs); __thrust_exec_check_disable__ template ::value> * = nullptr, detail::enable_if_t::value> * = nullptr> __host__ __device__ void swap(optional &lhs, optional &rhs) noexcept(noexcept(lhs.swap(rhs))) { return lhs.swap(rhs); } namespace detail { struct i_am_secret {}; } // namespace detail __thrust_exec_check_disable__ template ::value, detail::decay_t, T>> __host__ __device__ inline constexpr optional make_optional(U &&v) { return optional(std::forward(v)); } __thrust_exec_check_disable__ template __host__ __device__ inline constexpr optional make_optional(Args &&... args) { return optional(in_place, std::forward(args)...); } __thrust_exec_check_disable__ template __host__ __device__ inline constexpr optional make_optional(std::initializer_list il, Args &&... args) { return optional(in_place, il, std::forward(args)...); } #if THRUST_CPP_DIALECT >= 2017 template optional(T)->optional; #endif /// \exclude namespace detail { #ifdef THRUST_OPTIONAL_CPP14 __thrust_exec_check_disable__ template (), *std::declval())), detail::enable_if_t::value> * = nullptr> __host__ __device__ constexpr auto optional_map_impl(Opt &&opt, F &&f) { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); } __thrust_exec_check_disable__ template (), *std::declval())), detail::enable_if_t::value> * = nullptr> __host__ __device__ auto optional_map_impl(Opt &&opt, F &&f) { if (opt.has_value()) { detail::invoke(std::forward(f), *std::forward(opt)); return make_optional(monostate{}); } return optional(nullopt); } #else __thrust_exec_check_disable__ template (), *std::declval())), detail::enable_if_t::value> * = nullptr> __host__ __device__ constexpr auto optional_map_impl(Opt &&opt, F &&f) -> optional { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); } __thrust_exec_check_disable__ template (), *std::declval())), detail::enable_if_t::value> * = nullptr> __host__ __device__ auto optional_map_impl(Opt &&opt, F &&f) -> optional { if (opt.has_value()) { detail::invoke(std::forward(f), *std::forward(opt)); return monostate{}; } return nullopt; } #endif } // namespace detail /// Specialization for when `T` is a reference. `optional` acts similarly /// to a `T*`, but provides more operations and shows intent more clearly. /// /// *Examples*: /// /// ``` /// int i = 42; /// thrust::optional o = i; /// *o == 42; //true /// i = 12; /// *o = 12; //true /// &*o == &i; //true /// ``` /// /// Assignment has rebind semantics rather than assign-through semantics: /// /// ``` /// int j = 8; /// o = j; /// /// &*o == &j; //true /// ``` template class optional { 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`. \returns 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) &; __thrust_exec_check_disable__ template __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) &&; __thrust_exec_check_disable__ template __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) const &; __thrust_exec_check_disable__ template __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 &&; __thrust_exec_check_disable__ template __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); } #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` for some `U`. \returns 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) &; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR detail::invoke_result_t 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) &&; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR detail::invoke_result_t 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) const &; __thrust_exec_check_disable__ template __host__ __device__ constexpr detail::invoke_result_t 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 &&; __thrust_exec_check_disable__ template __host__ __device__ constexpr detail::invoke_result_t 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); } #endif #endif #if defined(THRUST_OPTIONAL_CPP14) && !defined(THRUST_OPTIONAL_GCC49) && \ !defined(THRUST_OPTIONAL_GCC54) && !defined(THRUST_OPTIONAL_GCC55) /// \brief Carries out some operation on the stored object if there is one. /// \returns 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 an `optional` is constructed from the /// return value of `std::invoke(std::forward(f), value())` and is /// returned. /// /// \group map /// \synopsis template constexpr auto map(F &&f) &; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR auto map(F &&f) & { return detail::optional_map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) &&; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR auto map(F &&f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) const&; __thrust_exec_check_disable__ template __host__ __device__ constexpr auto map(F &&f) const & { return detail::optional_map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) const&&; __thrust_exec_check_disable__ template __host__ __device__ constexpr auto map(F &&f) const && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #else /// \brief Carries out some operation on the stored object if there is one. /// \returns 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 an `optional` is constructed from the /// return value of `std::invoke(std::forward(f), value())` and is /// returned. /// /// \group map /// \synopsis template auto map(F &&f) &; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) & { return detail::optional_map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template auto map(F &&f) &&; __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } /// \group map /// \synopsis template auto map(F &&f) const&; __thrust_exec_check_disable__ template __host__ __device__ constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) const & { return detail::optional_map_impl(*this, std::forward(f)); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group map /// \synopsis template auto map(F &&f) const&&; __thrust_exec_check_disable__ template __host__ __device__ constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) const && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif /// \brief Calls `f` if the optional is empty /// \requires `std::invoke_result_t` must be void or convertible to /// `optional`. \effects If `*this` has a value, returns `*this`. /// Otherwise, if `f` returns `void`, calls `std::forward(f)` and returns /// `std::nullopt`. Otherwise, returns `std::forward(f)()`. /// /// \group or_else /// \synopsis template optional or_else (F &&f) &; __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) & { if (has_value()) return *this; std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) & { return has_value() ? *this : std::forward(f)(); } /// \group or_else /// \synopsis template optional or_else (F &&f) &&; __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) && { return has_value() ? std::move(*this) : std::forward(f)(); } /// \group or_else /// \synopsis template optional or_else (F &&f) const &; __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) const & { if (has_value()) return *this; std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional THRUST_OPTIONAL_CPP11_CONSTEXPR or_else(F &&f) const & { return has_value() ? *this : std::forward(f)(); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) const && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } /// \exclude __thrust_exec_check_disable__ template * = nullptr> __host__ __device__ optional or_else(F &&f) const && { return has_value() ? std::move(*this) : std::forward(f)(); } #endif /// \brief Maps the stored value with `f` if there is one, otherwise returns /// `u`. /// /// \details If there is a value stored, then `f` is called with `**this` /// and the value is returned. Otherwise `u` is returned. /// /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group map_or __thrust_exec_check_disable__ template __host__ __device__ U map_or(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } #endif /// \brief Maps the stored value with `f` if there is one, otherwise calls /// `u` and returns the result. /// /// \details If there is a value stored, then `f` is /// called with `**this` and the value is returned. Otherwise /// `std::forward(u)()` is returned. /// /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) &; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) /// &&; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) /// const &; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group map_or_else /// \synopsis template \nauto map_or_else(F &&f, U &&u) /// const &&; __thrust_exec_check_disable__ template __host__ __device__ detail::invoke_result_t map_or_else(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } #endif /// \returns `u` if `*this` has a value, otherwise an empty optional. __thrust_exec_check_disable__ template __host__ __device__ constexpr optional::type> conjunction(U &&u) const { using result = optional>; return has_value() ? result{u} : result{nullopt}; } /// \returns `rhs` if `*this` is empty, otherwise the current value. /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(const optional &rhs) & { return has_value() ? *this : rhs; } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(const optional &rhs) const & { return has_value() ? *this : rhs; } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(const optional &rhs) && { return has_value() ? std::move(*this) : rhs; } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(const optional &rhs) const && { return has_value() ? std::move(*this) : rhs; } #endif /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(optional &&rhs) & { return has_value() ? *this : std::move(rhs); } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(optional &&rhs) const & { return has_value() ? *this : std::move(rhs); } /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional disjunction(optional &&rhs) && { return has_value() ? std::move(*this) : std::move(rhs); } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group disjunction __thrust_exec_check_disable__ __host__ __device__ constexpr optional disjunction(optional &&rhs) const && { return has_value() ? std::move(*this) : std::move(rhs); } #endif /// Takes the value out of the optional, leaving it empty /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() & { optional ret = *this; reset(); return ret; } /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() const & { optional ret = *this; reset(); return ret; } /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() && { optional ret = std::move(*this); reset(); return ret; } #ifndef THRUST_OPTIONAL_NO_CONSTRR /// \group take __thrust_exec_check_disable__ __host__ __device__ optional take() const && { optional ret = std::move(*this); reset(); return ret; } #endif using value_type = T &; /// Constructs an optional that does not contain a value. /// \group ctor_empty __thrust_exec_check_disable__ __host__ __device__ constexpr optional() noexcept : m_value(nullptr) {} /// \group ctor_empty __thrust_exec_check_disable__ __host__ __device__ constexpr optional(nullopt_t) noexcept : m_value(nullptr) {} /// Copy constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. __thrust_exec_check_disable__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional(const optional &rhs) noexcept = default; /// Move constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. __thrust_exec_check_disable__ THRUST_OPTIONAL_CPP11_CONSTEXPR optional(optional &&rhs) = default; /// Constructs the stored value with `u`. /// \synopsis template constexpr optional(U &&u); __thrust_exec_check_disable__ template >::value> * = nullptr> __host__ __device__ constexpr optional(U &&u) : m_value(addressof(u)) { static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); } /// \exclude __thrust_exec_check_disable__ template __host__ __device__ constexpr explicit optional(const optional &rhs) : optional(*rhs) {} /// No-op __thrust_exec_check_disable__ ~optional() = default; /// Assignment to empty. /// /// Destroys the current value if there is one. __thrust_exec_check_disable__ __host__ __device__ optional &operator=(nullopt_t) noexcept { m_value = nullptr; return *this; } /// Copy assignment. /// /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise /// resets the stored value in `*this`. __thrust_exec_check_disable__ optional &operator=(const optional &rhs) = default; /// Rebinds this optional to `u`. /// /// \requires `U` must be an lvalue reference. /// \synopsis optional &operator=(U &&u); __thrust_exec_check_disable__ template >::value> * = nullptr> __host__ __device__ optional &operator=(U &&u) { static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); m_value = addressof(u); return *this; } /// Converting copy assignment operator. /// /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise /// resets the stored value in `*this`. __thrust_exec_check_disable__ template __host__ __device__ optional &operator=(const optional &rhs) { m_value = addressof(rhs.value()); return *this; } /// Constructs the value in-place, destroying the current one if there is /// one. /// /// \group emplace __thrust_exec_check_disable__ template __host__ __device__ T &emplace(Args &&... args) noexcept { static_assert(std::is_constructible::value, "T must be constructible with Args"); *this = nullopt; this->construct(std::forward(args)...); } /// Swaps this optional with the other. /// /// If neither optionals have a value, nothing happens. /// If both have a value, the values are swapped. /// If one has a value, it is moved to the other and the movee is left /// valueless. __thrust_exec_check_disable__ __host__ __device__ void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); } /// \returns a pointer to the stored value /// \requires a value is stored /// \group pointer /// \synopsis constexpr const T *operator->() const; __thrust_exec_check_disable__ __host__ __device__ constexpr const T *operator->() const { return m_value; } /// \group pointer /// \synopsis constexpr T *operator->(); __thrust_exec_check_disable__ __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T *operator->() { return m_value; } /// \returns the stored value /// \requires a value is stored /// \group deref /// \synopsis constexpr T &operator*(); __thrust_exec_check_disable__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &operator*() { return *m_value; } /// \group deref /// \synopsis constexpr const T &operator*() const; __thrust_exec_check_disable__ __host__ __device__ constexpr const T &operator*() const { return *m_value; } /// \returns whether or not the optional has a value /// \group has_value __thrust_exec_check_disable__ __host__ __device__ constexpr bool has_value() const noexcept { return m_value != nullptr; } /// \group has_value __thrust_exec_check_disable__ __host__ __device__ constexpr explicit operator bool() const noexcept { return m_value != nullptr; } /// \returns the contained value if there is one, otherwise throws /// [bad_optional_access] /// \group value /// synopsis constexpr T &value(); __host__ THRUST_OPTIONAL_CPP11_CONSTEXPR T &value() { if (has_value()) return *m_value; throw bad_optional_access(); } /// \group value /// \synopsis constexpr const T &value() const; __host__ THRUST_OPTIONAL_CPP11_CONSTEXPR const T &value() const { if (has_value()) return *m_value; throw bad_optional_access(); } /// \returns the stored value if there is one, otherwise returns `u` /// \group value_or __thrust_exec_check_disable__ template __host__ __device__ constexpr T value_or(U &&u) const & { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } /// \group value_or __thrust_exec_check_disable__ template __host__ __device__ THRUST_OPTIONAL_CPP11_CONSTEXPR T value_or(U &&u) && { static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } /// Destroys the stored value if one exists, making the optional empty __thrust_exec_check_disable__ void reset() noexcept { m_value = nullptr; } private: T *m_value; }; THRUST_NAMESPACE_END namespace std { // TODO SFINAE template struct hash> { __thrust_exec_check_disable__ __host__ __device__ ::std::size_t operator()(const THRUST_NS_QUALIFIER::optional &o) const { if (!o.has_value()) return 0; return std::hash>()(*o); } }; } // namespace std #endif // THRUST_CPP_DIALECT >= 2011