blob: d5939f5c2cf7967d7a541ef541a79c7d8d7ddb27 [file] [log] [blame]
/*
* Copyright (c) 2023 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 "__concepts.hpp"
#include "__config.hpp"
#include "__meta.hpp"
#include "__type_traits.hpp"
#include <cstddef>
namespace stdexec
{
namespace __tup
{
template <class _Ty, std::size_t _Idx>
struct __box
{
STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Ty __value;
};
template <class _Idx, class... _Ts>
struct __tuple;
template <std::size_t... _Idx, class... _Ts>
struct __tuple<__indices<_Idx...>, _Ts...> : __box<_Ts, _Idx>...
{};
template <class... _Ts>
STDEXEC_ATTRIBUTE((host, device))
__tuple(_Ts...) -> __tuple<__indices_for<_Ts...>, _Ts...>;
#if STDEXEC_GCC()
template <class... _Ts>
struct __mk_tuple
{
using __t = __tuple<__indices_for<_Ts...>, _Ts...>;
};
template <class... _Ts>
using __tuple_for = __t<__mk_tuple<_Ts...>>;
#else
template <class... _Ts>
using __tuple_for = __tuple<__indices_for<_Ts...>, _Ts...>;
#endif
template <std::size_t _Idx, class _Ty>
STDEXEC_ATTRIBUTE((always_inline))
constexpr _Ty&& __get(__box<_Ty, _Idx>&& __self) noexcept
{
return (_Ty&&)__self.__value;
}
template <std::size_t _Idx, class _Ty>
STDEXEC_ATTRIBUTE((always_inline))
constexpr _Ty& __get(__box<_Ty, _Idx>& __self) noexcept
{
return __self.__value;
}
template <std::size_t _Idx, class _Ty>
STDEXEC_ATTRIBUTE((always_inline))
constexpr const _Ty& __get(const __box<_Ty, _Idx>& __self) noexcept
{
return __self.__value;
}
template <std::size_t... _Idx, class... _Ts>
void __tuple_like_(const __tuple<__indices<_Idx...>, _Ts...>&);
template <class _Tup>
concept __tuple_like = requires(_Tup& __tup) { __tup::__tuple_like_(__tup); };
struct __apply_
{
template <class _Fun, class _Tuple, std::size_t... _Idx, class... _Ts>
requires __callable<_Fun, __copy_cvref_t<_Tuple, _Ts>...>
constexpr auto operator()(
_Fun&& __fun, _Tuple&& __tup,
const __tuple<
__indices<_Idx...>,
_Ts...>*) noexcept(__nothrow_callable<_Fun, __copy_cvref_t<_Tuple,
_Ts>...>)
-> __call_result_t<_Fun, __copy_cvref_t<_Tuple, _Ts>...>
{
return ((_Fun&&)__fun)(
static_cast<__copy_cvref_t<_Tuple, __box<_Ts, _Idx>>&&>(__tup)
.__value...);
}
};
template <class _Fun, __tuple_like _Tuple>
STDEXEC_ATTRIBUTE((always_inline))
constexpr auto __apply(_Fun&& __fun, _Tuple&& __tup) noexcept(
noexcept(__apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup)))
-> decltype(__apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup))
{
return __apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup);
}
} // namespace __tup
using __tup::__tuple;
// So we can use __tuple as a typelist and ignore the first template parameter
template <class _Fn, class _Idx, class... _Ts>
requires __minvocable<_Fn, _Ts...>
struct __uncurry_<_Fn, __tuple<_Idx, _Ts...>>
{
using __t = __minvoke<_Fn, _Ts...>;
};
} // namespace stdexec