blob: b5f964516fb8d1699587183f48bd233bbb8bde0b [file] [log] [blame]
/*
* Copyright (c) 2021-2022 NVIDIA Corporation
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://llvm.org/LICENSE.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "__detail/__concepts.hpp"
#include "__detail/__config.hpp"
#include "concepts.hpp"
#include <version>
#if __cpp_impl_coroutine >= 201902 && __cpp_lib_coroutine >= 201902
#include <coroutine>
namespace __coro = std;
#elif defined(__cpp_coroutines) && __has_include(<experimental/coroutine>)
#include <experimental/coroutine>
namespace __coro = std::experimental;
#else
#define STDEXEC_STD_NO_COROUTINES_ 1
#endif
namespace stdexec
{
#if !STDEXEC_STD_NO_COROUTINES_
// Define some concepts and utilities for working with awaitables
template <class _Tp>
concept __await_suspend_result =
__one_of<_Tp, void, bool> ||
__is_instance_of<_Tp, __coro::coroutine_handle>;
template <class _Awaiter, class _Promise>
concept __with_await_suspend =
same_as<_Promise, void> || //
requires(_Awaiter& __awaiter, __coro::coroutine_handle<_Promise> __h) {
{
__awaiter.await_suspend(__h)
} -> __await_suspend_result;
};
template <class _Awaiter, class _Promise = void>
concept __awaiter = //
requires(_Awaiter& __awaiter) {
__awaiter.await_ready() ? 1 : 0;
__awaiter.await_resume();
} && //
__with_await_suspend<_Awaiter, _Promise>;
#if STDEXEC_MSVC()
// MSVCBUG
// https://developercommunity.visualstudio.com/t/operator-co_await-not-found-in-requires/10452721
template <class _Awaitable>
void __co_await_constraint(_Awaitable&& __awaitable)
requires requires { operator co_await((_Awaitable&&)__awaitable); };
#endif
template <class _Awaitable>
decltype(auto) __get_awaiter(_Awaitable&& __awaitable, void*)
{
if constexpr (requires { ((_Awaitable&&)__awaitable).operator co_await(); })
{
return ((_Awaitable&&)__awaitable).operator co_await();
}
else if constexpr (requires {
#if STDEXEC_MSVC()
__co_await_constraint((_Awaitable&&)__awaitable);
#else
operator co_await((_Awaitable&&) __awaitable);
#endif
})
{
return operator co_await((_Awaitable&&)__awaitable);
}
else
{
return (_Awaitable&&)__awaitable;
}
}
template <class _Awaitable, class _Promise>
decltype(auto) __get_awaiter(_Awaitable&& __awaitable, _Promise* __promise)
requires requires { __promise->await_transform((_Awaitable&&)__awaitable); }
{
if constexpr (requires {
__promise->await_transform((_Awaitable&&)__awaitable)
.
operator co_await();
})
{
return __promise->await_transform((_Awaitable&&)__awaitable)
.
operator co_await();
}
else if constexpr (requires {
#if STDEXEC_MSVC()
__co_await_constraint(__promise->await_transform(
(_Awaitable&&)__awaitable));
#else
operator co_await(__promise->await_transform((_Awaitable&&) __awaitable));
#endif
})
{
return operator co_await(
__promise->await_transform((_Awaitable&&)__awaitable));
}
else
{
return __promise->await_transform((_Awaitable&&)__awaitable);
}
}
template <class _Awaitable, class _Promise = void>
concept __awaitable = //
requires(_Awaitable&& __awaitable, _Promise* __promise) {
{
stdexec::__get_awaiter((_Awaitable&&)__awaitable, __promise)
} -> __awaiter<_Promise>;
};
template <class _Tp>
_Tp& __as_lvalue(_Tp&&);
template <class _Awaitable, class _Promise = void>
requires __awaitable<_Awaitable, _Promise>
using __await_result_t =
decltype(stdexec::__as_lvalue(
stdexec::__get_awaiter(std::declval<_Awaitable>(),
(_Promise*)nullptr))
.await_resume());
#else
template <class _Awaitable, class _Promise = void>
concept __awaitable = false;
template <class _Awaitable, class _Promise = void>
requires __awaitable<_Awaitable, _Promise>
using __await_result_t = void;
#endif
} // namespace stdexec