rosa/inc/alsk/skeleton/link/args/traits.h
2021-05-10 18:14:24 +02:00

227 lines
5.6 KiB
C++

#ifndef ALSK_ALSK_SKELETON_LINK_ARGS_TRAITS_H
#define ALSK_ALSK_SKELETON_LINK_ARGS_TRAITS_H
#include <functional>
#include <type_traits>
#include <utility>
#include <tmp/pack.h>
#include <tmp/traits.h>
#include "placeholders.h"
namespace alsk {
namespace arg {
/**
* @brief true if the given type is a placeholder for a parameter
*/
template<typename T> struct IsP: std::false_type {};
template<std::size_t I> struct IsP<P<I>>: std::true_type {};
template<typename T>
constexpr bool isP = IsP<T>::value;
/**
* @brief true if the given type is a placeholder for a returned value
*/
template<typename T> struct IsR: std::false_type {};
template<std::size_t I> struct IsR<R<I>>: std::true_type {};
template<typename T>
constexpr bool isR = IsR<T>::value;
/**
* @brief true if the given type is a placeholder for a contextual argument
*/
template<typename T> struct IsC: std::false_type {};
template<std::size_t I> struct IsC<C<I>>: std::true_type {};
template<typename T>
constexpr bool isC = IsC<T>::value;
/**
* @brief placeholders group
*/
template<typename P_, typename R_, typename C_>
struct Placeholders {
using P = tmp::AsPack<std::decay_t<P_>>;
using R = tmp::AsPack<std::decay_t<R_>>;
using C = tmp::AsPack<std::decay_t<C_>>;
};
}
/**
* @brief apply type mods from A to B
*/
template<typename, typename B>
struct ApplyTypeModsImpl {
using type = B; // TODO: std::decay_t<B>
};
template<typename A, typename B>
struct ApplyTypeModsImpl<A const&, B> {
using type = std::decay_t<B> const&;
};
template<typename A, typename B>
using ApplyTypeMods = typename ApplyTypeModsImpl<A, B>::type;
/**
* @brief ArgType
*/
template<typename T, typename, typename=void>
struct ArgTypeImpl {
using type = T;
};
template<typename A, typename Placeholders>
struct ArgTypeImpl<A, Placeholders, std::enable_if_t<arg::isP<std::decay_t<A>>>> {
using type = tmp::PackGet<typename Placeholders::P, std::decay_t<A>::value>;
};
template<typename A, typename Placeholders>
struct ArgTypeImpl<A, Placeholders, std::enable_if_t<arg::isR<std::decay_t<A>>>> {
using type = tmp::PackGet<typename Placeholders::R, std::decay_t<A>::value>;
};
template<typename A, typename Placeholders>
struct ArgTypeImpl<A, Placeholders, std::enable_if_t<arg::isC<std::decay_t<A>>>> {
using type = tmp::PackGet<typename Placeholders::C, std::decay_t<A>::value>;
};
template<typename T, typename Placeholders>
using ArgType = typename ArgTypeImpl<T, Placeholders>::type;
/**
* @brief ArgGet
*/
template<typename, typename=void> struct ArgGet;
template<>
struct ArgGet<void> {
template<typename P, typename R, typename C>
static void get(P&&, R&&, C&&) {}
};
template<typename A>
struct ArgGet<A, std::enable_if_t<arg::isP<std::decay_t<A>>>> {
template<typename P, typename R, typename C>
static auto get(P&& p, R&&, C&&)
-> /*ApplyTypeMods<A,*/ // TODO: does not work
ArgType<A, arg::Placeholders<P, tmp::Pack<>, tmp::Pack<>>>
/*>*/ {
return std::get<std::decay_t<A>::value>(std::forward<P>(p));
}
};
template<typename A>
struct ArgGet<A, std::enable_if_t<arg::isR<std::decay_t<A>>>> {
template<typename P, typename R, typename C>
static auto get(P&&, R&& r, C&&)
-> ApplyTypeMods<A,
ArgType<A, arg::Placeholders<tmp::Pack<>, R, tmp::Pack<>>>
> {
return std::get<std::decay_t<A>::value>(std::forward<R>(r));
}
};
template<typename A>
struct ArgGet<A, std::enable_if_t<arg::isC<std::decay_t<A>>>> {
template<typename P, typename R, typename C>
static auto get(P&&, R&&, C&& x)
-> ApplyTypeMods<A,
ArgType<A, arg::Placeholders<tmp::Pack<>, tmp::Pack<>, C>>
> {
return std::get<std::decay_t<A>::value>(std::forward<C>(x));
}
};
/**
* @brief IsPlaceholder
*/
namespace impl {
template<typename A>
struct IsPlaceholder:
std::integral_constant<bool,
arg::isP<std::decay_t<A>> or arg::isR<std::decay_t<A>> or arg::isC<std::decay_t<A>>
> {};
template<typename A>
constexpr bool isPlaceholder = IsPlaceholder<A>::value;
}
/**
* @brief ArgFilter
*/
template<typename, typename = void> struct ArgFilterImpl;
template<typename Ret, typename T, typename... Ts>
struct ArgFilterImpl<Ret(T, Ts...), std::enable_if_t<impl::isPlaceholder<T>>> {
using type = tmp::FunctionCat<Ret(T), typename ArgFilterImpl<Ret(Ts...)>::type>;
};
template<typename Ret, typename T, typename... Ts>
struct ArgFilterImpl<Ret(T, Ts...), std::enable_if_t<!impl::isPlaceholder<T>>> {
using type = typename ArgFilterImpl<Ret(Ts...)>::type;
};
template<typename Ret>
struct ArgFilterImpl<Ret()> {
using type = Ret();
};
template<typename F>
using ArgFilter = typename ArgFilterImpl<F>::type;
/**
* @brief RealTypeImpl
* @param T a type to solve
* @param Placeholders the placeholders list
*/
template<typename T, typename Placeholders>
struct RealTypeImpl {
using type = ArgType<T, Placeholders>;
};
/**
* @brief RealType
* @param T a type to solve
* @param Placeholders the placeholders list
*/
template<typename T, typename Placeholders>
using RealType = typename RealTypeImpl<T, Placeholders>::type;
/**
* @brief RealSignature
*/
template<typename, typename> struct RealSignatureImpl;
template<typename Ret, typename... Ps, typename Placeholders>
struct RealSignatureImpl<Ret(Ps...), Placeholders> {
// using type = Ret(*)(typename RealType<Ps, P, R>::type...); // issue with const& parameters
using type = std::function<Ret(RealType<Ps, Placeholders>...)>;
};
template<typename T, typename Placeholders>
using RealSignature = typename RealSignatureImpl<T, Placeholders>::type;
/**
* @brief Returns
*/
template<typename> struct ReturnsImpl;
template<typename... Fs>
struct ReturnsImpl<tmp::Pack<Fs...>> {
using type = tmp::Pack<tmp::ReturnType<Fs>...>;
};
template<typename T>
using Returns = typename ReturnsImpl<T>::type;
}
#endif