1 /*
2  * Copyright (c) 2021-2024 NVIDIA Corporation
3  *
4  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5  * (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  *
8  *   https://llvm.org/LICENSE.txt
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include "__execution_fwd.hpp"
19 
20 // include these after __execution_fwd.hpp
21 #include "__concepts.hpp"
22 #include "__type_traits.hpp"
23 
24 #include <exception>
25 #include <memory>
26 #include <new>
27 #include <utility>
28 
29 namespace stdexec
30 {
31 namespace __opt
32 {
33 struct __bad_optional_access : std::exception
34 {
whatstdexec::__opt::__bad_optional_access35     const char* what() const noexcept override
36     {
37         return "stdexec::__optional: bad access";
38     }
39 };
40 
41 inline constexpr struct __nullopt_t
42 {
43 } __nullopt{};
44 
45 // A simplified version of std::optional for better compile times
46 template <class _Tp>
47 struct __optional
48 {
49     static_assert(destructible<_Tp>);
50 
51     union
52     {
53         _Tp __value;
54     };
55 
56     bool __has_value = false;
57 
__optionalstdexec::__opt::__optional58     __optional() noexcept {}
59 
__optionalstdexec::__opt::__optional60     __optional(__nullopt_t) noexcept {}
61 
62     __optional(__optional&&) = delete; // immovable for simplicity's sake
63 
64     template <__not_decays_to<__optional> _Up>
65         requires constructible_from<_Tp, _Up>
__optionalstdexec::__opt::__optional66     __optional(_Up&& __v) : __value(static_cast<_Up&&>(__v)), __has_value(true)
67     {}
68 
69     template <class... _Us>
70         requires constructible_from<_Tp, _Us...>
__optionalstdexec::__opt::__optional71     __optional(std::in_place_t, _Us&&... __us) :
72         __value(static_cast<_Us&&>(__us)...), __has_value(true)
73     {}
74 
~__optionalstdexec::__opt::__optional75     ~__optional()
76     {
77         if (__has_value)
78         {
79             std::destroy_at(std::addressof(__value));
80         }
81     }
82 
83     template <class... _Us>
84         requires constructible_from<_Tp, _Us...>
emplacestdexec::__opt::__optional85     _Tp& emplace(_Us&&... __us) noexcept(
86         __nothrow_constructible_from<_Tp, _Us...>)
87     {
88         reset(); // sets __has_value to false in case the next line throws
89         ::new (&__value) _Tp{static_cast<_Us&&>(__us)...};
90         __has_value = true;
91         return __value;
92     }
93 
valuestdexec::__opt::__optional94     _Tp& value() &
95     {
96         if (!__has_value)
97         {
98             throw __bad_optional_access();
99         }
100         return __value;
101     }
102 
valuestdexec::__opt::__optional103     const _Tp& value() const&
104     {
105         if (!__has_value)
106         {
107             throw __bad_optional_access();
108         }
109         return __value;
110     }
111 
valuestdexec::__opt::__optional112     _Tp&& value() &&
113     {
114         if (!__has_value)
115         {
116             throw __bad_optional_access();
117         }
118         return static_cast<_Tp&&>(__value);
119     }
120 
operator *stdexec::__opt::__optional121     _Tp& operator*() & noexcept
122     {
123         STDEXEC_ASSERT(__has_value);
124         return __value;
125     }
126 
operator *stdexec::__opt::__optional127     const _Tp& operator*() const& noexcept
128     {
129         STDEXEC_ASSERT(__has_value);
130         return __value;
131     }
132 
operator *stdexec::__opt::__optional133     _Tp&& operator*() && noexcept
134     {
135         STDEXEC_ASSERT(__has_value);
136         return static_cast<_Tp&&>(__value);
137     }
138 
operator ->stdexec::__opt::__optional139     _Tp* operator->() & noexcept
140     {
141         STDEXEC_ASSERT(__has_value);
142         return &__value;
143     }
144 
operator ->stdexec::__opt::__optional145     const _Tp* operator->() const& noexcept
146     {
147         STDEXEC_ASSERT(__has_value);
148         return &__value;
149     }
150 
has_valuestdexec::__opt::__optional151     bool has_value() const noexcept
152     {
153         return __has_value;
154     }
155 
resetstdexec::__opt::__optional156     void reset() noexcept
157     {
158         if (__has_value)
159         {
160             std::destroy_at(std::addressof(__value));
161             __has_value = false;
162         }
163     }
164 };
165 } // namespace __opt
166 
167 using __opt::__bad_optional_access;
168 using __opt::__nullopt;
169 using __opt::__optional;
170 } // namespace stdexec
171