17 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
18 #include <Kokkos_Macros.hpp>
20 "Including non-public Kokkos header files is not allowed.");
22 #ifndef KOKKOS_FUTURE_HPP
23 #define KOKKOS_FUTURE_HPP
27 #include <Kokkos_Macros.hpp>
28 #if defined(KOKKOS_ENABLE_TASKDAG)
30 #include <Kokkos_Core_fwd.hpp>
31 #include <Kokkos_TaskScheduler_fwd.hpp>
34 #include <impl/Kokkos_TaskQueue.hpp>
35 #include <impl/Kokkos_TaskResult.hpp>
36 #include <impl/Kokkos_TaskBase.hpp>
39 #include <Kokkos_Concepts.hpp>
49 template <
typename ValueType,
typename ExecutionSpace,
typename QueueType>
50 class BasicFuture<ValueType, SimpleTaskScheduler<ExecutionSpace, QueueType>> {
52 using value_type = ValueType;
53 using execution_space = ExecutionSpace;
54 using scheduler_type = SimpleTaskScheduler<ExecutionSpace, QueueType>;
55 using queue_type =
typename scheduler_type::task_queue_type;
58 template <
class,
class>
59 friend class SimpleTaskScheduler;
60 template <
class,
class>
61 friend class BasicFuture;
63 using task_base_type =
typename scheduler_type::task_base_type;
64 using task_queue_type =
typename scheduler_type::task_queue_type;
66 using task_queue_traits =
typename scheduler_type::task_queue_traits;
67 using task_scheduling_info_type =
68 typename scheduler_type::task_scheduling_info_type;
70 using result_storage_type = Impl::TaskResultStorage<
72 Impl::SchedulingInfoStorage<Impl::RunnableTaskBase<task_queue_traits>,
73 task_scheduling_info_type>>;
75 OwningRawPtr<task_base_type> m_task =
nullptr;
77 KOKKOS_INLINE_FUNCTION
78 explicit BasicFuture(task_base_type* task) : m_task(task) {
85 KOKKOS_INLINE_FUNCTION
86 BasicFuture() noexcept : m_task(
nullptr) {}
88 KOKKOS_INLINE_FUNCTION
89 BasicFuture(BasicFuture&& rhs) noexcept : m_task(std::move(rhs.m_task)) {
93 KOKKOS_INLINE_FUNCTION
94 BasicFuture(BasicFuture
const& rhs)
97 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
98 if (m_task) m_task->increment_reference_count();
101 KOKKOS_INLINE_FUNCTION
102 BasicFuture& operator=(BasicFuture&& rhs) noexcept {
103 if (m_task != rhs.m_task) {
106 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
112 rhs.m_task =
nullptr;
116 KOKKOS_INLINE_FUNCTION
117 BasicFuture& operator=(BasicFuture
const& rhs) {
118 if (m_task != rhs.m_task) {
121 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
123 if (m_task !=
nullptr) {
124 m_task->increment_reference_count();
131 template <
class T,
class S>
132 KOKKOS_INLINE_FUNCTION BasicFuture(
133 BasicFuture<T, S>&& rhs) noexcept
134 : m_task(std::move(rhs.m_task)) {
135 static_assert(std::is_void<scheduler_type>::value ||
136 std::is_same<scheduler_type, S>::value,
137 "Moved Futures must have the same scheduler");
140 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
141 "Moved Futures must have the same value_type");
144 rhs.m_task =
nullptr;
147 template <
class T,
class S>
148 KOKKOS_INLINE_FUNCTION BasicFuture(
149 BasicFuture<T, S>
const& rhs)
152 static_assert(std::is_void<scheduler_type>::value ||
153 std::is_same<scheduler_type, S>::value,
154 "Copied Futures must have the same scheduler");
157 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
158 "Copied Futures must have the same value_type");
160 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
161 if (m_task) m_task->increment_reference_count();
164 template <
class T,
class S>
165 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>
const& rhs) {
166 static_assert(std::is_void<scheduler_type>::value ||
167 std::is_same<scheduler_type, S>::value,
168 "Assigned Futures must have the same scheduler");
171 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
172 "Assigned Futures must have the same value_type");
174 if (m_task != rhs.m_task) {
177 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
178 if (m_task !=
nullptr) {
179 m_task->increment_reference_count();
185 template <
class T,
class S>
186 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>&& rhs) {
187 static_assert(std::is_void<scheduler_type>::value ||
188 std::is_same<scheduler_type, S>::value,
189 "Assigned Futures must have the same scheduler");
192 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
193 "Assigned Futures must have the same value_type");
195 if (m_task != rhs.m_task) {
198 *
static_cast<task_base_type* volatile*
>(&m_task) = rhs.m_task;
204 rhs.m_task =
nullptr;
208 KOKKOS_INLINE_FUNCTION
209 ~BasicFuture() noexcept { clear(); }
213 KOKKOS_INLINE_FUNCTION
214 void clear() noexcept {
216 bool should_delete = m_task->decrement_and_check_reference_count();
218 static_cast<task_queue_type*
>(m_task->ready_queue_base_ptr())
219 ->deallocate(std::move(*m_task));
223 *
static_cast<task_base_type* volatile*
>(&m_task) =
nullptr;
226 KOKKOS_INLINE_FUNCTION
227 bool is_null() const noexcept {
return m_task ==
nullptr; }
229 KOKKOS_INLINE_FUNCTION
230 bool is_ready() const noexcept {
231 return (m_task ==
nullptr) || m_task->wait_queue_is_consumed();
234 KOKKOS_INLINE_FUNCTION
235 const typename Impl::TaskResult<ValueType>::reference_type
get()
const {
236 KOKKOS_EXPECTS(is_ready());
237 return static_cast<result_storage_type*
>(m_task)->value_reference();
246 template <
typename ValueType,
typename Scheduler>
249 template <
typename,
typename>
250 friend class BasicTaskScheduler;
251 template <
typename,
typename>
252 friend class BasicFuture;
253 friend class Impl::TaskBase;
254 template <
typename,
typename,
typename>
255 friend class Impl::Task;
262 using scheduler_type = Scheduler;
263 using queue_type =
typename scheduler_type::queue_type;
264 using execution_space =
typename scheduler_type::execution_space;
265 using value_type = ValueType;
272 using task_base = Impl::TaskBase;
276 KOKKOS_INLINE_FUNCTION
explicit BasicFuture(task_base* task)
278 if (task) queue_type::assign(&m_task, task);
286 KOKKOS_INLINE_FUNCTION
287 bool is_null()
const {
return nullptr == m_task; }
289 KOKKOS_INLINE_FUNCTION
290 int reference_count()
const {
291 return nullptr != m_task ? m_task->reference_count() : 0;
296 KOKKOS_INLINE_FUNCTION
298 if (m_task) queue_type::assign(&m_task,
nullptr);
303 KOKKOS_INLINE_FUNCTION
304 ~BasicFuture() { clear(); }
308 KOKKOS_INLINE_FUNCTION
309 BasicFuture() noexcept : m_task(
nullptr) {}
311 KOKKOS_INLINE_FUNCTION
312 BasicFuture(BasicFuture&& rhs) noexcept : m_task(rhs.m_task) {
313 rhs.m_task =
nullptr;
316 KOKKOS_INLINE_FUNCTION
317 BasicFuture(
const BasicFuture& rhs) : m_task(nullptr) {
318 if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
321 KOKKOS_INLINE_FUNCTION
322 BasicFuture& operator=(BasicFuture&& rhs) noexcept {
325 rhs.m_task =
nullptr;
329 KOKKOS_INLINE_FUNCTION
330 BasicFuture& operator=(BasicFuture
const& rhs) {
331 if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
337 template <
class T,
class S>
338 KOKKOS_INLINE_FUNCTION BasicFuture(
339 BasicFuture<T, S>&& rhs) noexcept
340 : m_task(rhs.m_task) {
341 static_assert(std::is_void<scheduler_type>::value ||
342 std::is_same<scheduler_type, S>::value,
343 "Assigned Futures must have the same scheduler");
346 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
347 "Assigned Futures must have the same value_type");
352 template <
class T,
class S>
353 KOKKOS_INLINE_FUNCTION BasicFuture(
354 BasicFuture<T, S>
const& rhs)
356 static_assert(std::is_void<scheduler_type>::value ||
357 std::is_same<scheduler_type, S>::value,
358 "Assigned Futures must have the same scheduler");
361 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
362 "Assigned Futures must have the same value_type");
364 if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
367 template <
class T,
class S>
368 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>
const& rhs) {
369 static_assert(std::is_void<scheduler_type>::value ||
370 std::is_same<scheduler_type, S>::value,
371 "Assigned Futures must have the same scheduler");
374 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
375 "Assigned Futures must have the same value_type");
377 if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task);
381 template <
class T,
class S>
382 KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture<T, S>&& rhs) {
383 static_assert(std::is_void<scheduler_type>::value ||
384 std::is_same<scheduler_type, S>::value,
385 "Assigned Futures must have the same scheduler");
388 std::is_void<value_type>::value || std::is_same<value_type, T>::value,
389 "Assigned Futures must have the same value_type");
399 KOKKOS_INLINE_FUNCTION
400 int is_ready() const noexcept {
401 return (
nullptr == m_task) ||
402 (
reinterpret_cast<task_base*
>(task_base::LockTag) == m_task->m_wait);
405 KOKKOS_INLINE_FUNCTION
406 const typename Impl::TaskResult<ValueType>::reference_type
get()
const {
407 if (
nullptr == m_task) {
408 Kokkos::abort(
"Kokkos:::Future::get ERROR: is_null()");
410 return Impl::TaskResult<ValueType>::get(m_task);
415 template <
typename,
typename ExecSpace =
void>
416 struct is_future :
public std::false_type {};
418 template <
typename ValueType,
typename Scheduler,
typename ExecSpace>
419 struct is_future<BasicFuture<ValueType, Scheduler>, ExecSpace>
420 : std::bool_constant<
421 std::is_same<ExecSpace, typename Scheduler::execution_space>::value ||
422 std::is_void<ExecSpace>::value> {};
430 template <
class Arg1,
class Arg2>
431 class ResolveFutureArgOrder {
433 enum { Arg1_is_space = Kokkos::is_space<Arg1>::value };
434 enum { Arg2_is_space = Kokkos::is_space<Arg2>::value };
435 enum { Arg1_is_value = !Arg1_is_space && !std::is_void<Arg1>::value };
436 enum { Arg2_is_value = !Arg2_is_space && !std::is_void<Arg2>::value };
438 static_assert(!(Arg1_is_space && Arg2_is_space),
439 "Future cannot be given two spaces");
441 static_assert(!(Arg1_is_value && Arg2_is_value),
442 "Future cannot be given two value types");
445 std::conditional_t<Arg1_is_value, Arg1,
446 std::conditional_t<Arg2_is_value, Arg2, void>>;
448 using execution_space =
typename std::conditional_t<
450 std::conditional_t<Arg2_is_space, Arg2, void>>::execution_space;
453 using type = BasicFuture<value_type, TaskScheduler<execution_space>>;
465 template <
class Arg1 =
void,
class Arg2 =
void>
466 using Future =
typename Impl::ResolveFutureArgOrder<Arg1, Arg2>::type;
bool is_null(const boost::shared_ptr< T > &p)