Added utility functions for modifying type argument lists.
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
#if !defined(MIJIN_UTIL_TRAITS_HPP_INCLUDED)
|
||||
#define MIJIN_UTIL_TRAITS_HPP_INCLUDED 1
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
@@ -24,6 +26,61 @@ namespace mijin
|
||||
struct Type_; // use as typevar
|
||||
struct Any_; // use as placeholder in templates
|
||||
|
||||
template<std::size_t idx = 0>
|
||||
struct TypeVar {};
|
||||
|
||||
template<typename T>
|
||||
struct Type
|
||||
{
|
||||
using type_t = T;
|
||||
|
||||
template<typename TOther>
|
||||
constexpr bool operator==(Type<TOther>) const noexcept
|
||||
{
|
||||
return std::is_same_v<T, TOther>;
|
||||
}
|
||||
|
||||
template<typename TOther>
|
||||
constexpr bool operator!=(Type<TOther>) const noexcept
|
||||
{
|
||||
return !std::is_same_v<T, TOther>;
|
||||
}
|
||||
};
|
||||
|
||||
template<auto func>
|
||||
struct type_func
|
||||
{
|
||||
template<typename... Types>
|
||||
static constexpr auto value = func(Type<Types>()...);
|
||||
|
||||
template<typename... Types>
|
||||
struct type {
|
||||
static constexpr auto value = func(Type<Types>()...);
|
||||
};
|
||||
};
|
||||
|
||||
template<auto... Values>
|
||||
struct value_list
|
||||
{
|
||||
template<typename TFunc>
|
||||
static constexpr auto apply(TFunc&& func)
|
||||
{
|
||||
return std::invoke(std::forward<TFunc>(func), Values...);
|
||||
}
|
||||
|
||||
template<typename TFunc>
|
||||
static constexpr void forEach(TFunc func)
|
||||
{
|
||||
(std::invoke(func, Values), ...);
|
||||
}
|
||||
|
||||
template<typename TFunc>
|
||||
static constexpr void forEachStatic(TFunc func)
|
||||
{
|
||||
(std::invoke(func, std::integral_constant<std::remove_cvref_t<decltype(Values)>, Values>()), ...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct always_false
|
||||
{
|
||||
@@ -42,46 +99,207 @@ struct always_false_val
|
||||
template<auto V>
|
||||
inline constexpr bool always_false_val_v = always_false_val<V>::value;
|
||||
|
||||
template<template<typename> typename TFilter, typename... TArgs>
|
||||
struct TypeFilter;
|
||||
|
||||
template<template<typename> typename TFilter>
|
||||
struct TypeFilter<TFilter>
|
||||
template<std::size_t I, typename TArg, typename... TArgs>
|
||||
struct TypeAtHelper
|
||||
{
|
||||
using type_t = std::tuple<>;
|
||||
using type_t = typename TypeAtHelper<I-1, TArgs...>::type_t;
|
||||
};
|
||||
|
||||
template<template<typename> typename TFilter, typename TFirst, typename... TArgs>
|
||||
struct TypeFilter<TFilter, TFirst, TArgs...>
|
||||
template<typename TArg, typename... TArgs>
|
||||
struct TypeAtHelper<0, TArg, TArgs...>
|
||||
{
|
||||
static consteval auto makeTypeHelper()
|
||||
{
|
||||
using base_t = typename TypeFilter<TFilter, TArgs...>::type_t;
|
||||
using type_t = TArg;
|
||||
};
|
||||
template<std::size_t I, typename... TArgs>
|
||||
using type_at_t = typename TypeAtHelper<I, TArgs...>::type_t;
|
||||
|
||||
// note: not using decltype, as the compiler might think it is being evaluated
|
||||
if constexpr (!TFilter<TFirst>::value) {
|
||||
return static_cast<base_t*>(nullptr);
|
||||
template<typename TFrom, template<typename...> typename TTo>
|
||||
struct copy_args;
|
||||
|
||||
template<template<typename...> typename TFrom, template<typename...> typename TTo, typename... TArgs>
|
||||
struct copy_args<TFrom<TArgs...>, TTo> {
|
||||
using type = TTo<TArgs...>;
|
||||
};
|
||||
|
||||
template<typename TFrom, template<typename...> typename TTo>
|
||||
using copy_args_t = typename copy_args<TFrom, TTo>::type;
|
||||
|
||||
template<typename TTmpl, typename TFrom, typename TTo>
|
||||
struct replace_type;
|
||||
|
||||
template<template<typename...> typename TTmpl, typename TFrom, typename TTo, typename... TArgs>
|
||||
struct replace_type<TTmpl<TArgs...>, TFrom, TTo>
|
||||
{
|
||||
using type = TTmpl<std::conditional_t<std::is_same_v<TArgs, TFrom>, TTo, TArgs>...>;
|
||||
};
|
||||
|
||||
template<typename TTmpl, typename TFrom, typename TTo>
|
||||
using replace_type_t = typename replace_type<TTmpl, TFrom, TTo>::type;
|
||||
|
||||
template<typename TTmpl, std::size_t offset, typename... TTypes>
|
||||
struct ReplaceTypevarsHelper;
|
||||
|
||||
template<typename TTmpl, std::size_t offset, typename TFirst, typename... TMore>
|
||||
struct ReplaceTypevarsHelper<TTmpl, offset, TFirst, TMore...>
|
||||
{
|
||||
using type = replace_type_t<typename ReplaceTypevarsHelper<TTmpl, offset+1, TMore...>::type, TypeVar<offset>, TFirst>;
|
||||
};
|
||||
|
||||
template<typename TTmpl, std::size_t offset>
|
||||
struct ReplaceTypevarsHelper<TTmpl, offset>
|
||||
{
|
||||
using type = TTmpl;
|
||||
};
|
||||
|
||||
template<typename TTmpl, typename... TArgs>
|
||||
using replace_typevars_t = typename ReplaceTypevarsHelper<TTmpl, 0, TArgs...>::type;
|
||||
|
||||
template<typename TTmpl, typename TType>
|
||||
struct prepend_type;
|
||||
|
||||
template<template<typename...> typename TTmpl, typename TType, typename... TArgs>
|
||||
struct prepend_type<TTmpl<TArgs...>, TType>
|
||||
{
|
||||
using type = TTmpl<TType, TArgs...>;
|
||||
};
|
||||
|
||||
template<typename TTmpl, typename TType>
|
||||
using prepend_type_t = typename prepend_type<TTmpl, TType>::type;
|
||||
|
||||
template<typename... TTmpl>
|
||||
struct concat_types;
|
||||
|
||||
template<template<typename...> typename TTmplA, template<typename...> typename TTmplB, typename... TArgsA, typename... TArgsB>
|
||||
struct concat_types<TTmplA<TArgsA...>, TTmplB<TArgsB...>>
|
||||
{
|
||||
using type = TTmplA<TArgsA..., TArgsB...>;
|
||||
};
|
||||
|
||||
template<typename TTmplA, typename TTmplB, typename... TMore>
|
||||
struct concat_types<TTmplA, TTmplB, TMore...>
|
||||
{
|
||||
using type = typename concat_types<typename concat_types<TTmplA, TTmplB>::type, TMore...>::type;
|
||||
};
|
||||
|
||||
template<typename TTmpl>
|
||||
struct concat_types<TTmpl>
|
||||
{
|
||||
using type = TTmpl;
|
||||
};
|
||||
|
||||
template<typename... TTmpl>
|
||||
using concat_types_t = typename concat_types<TTmpl...>::type;
|
||||
|
||||
template<typename TTmpl, std::size_t count = 1>
|
||||
struct drop_types;
|
||||
|
||||
template<template<typename...> typename TTmpl, std::size_t count, typename TFirst, typename... TArgs>
|
||||
struct drop_types<TTmpl<TFirst, TArgs...>, count>
|
||||
{
|
||||
using type = std::remove_pointer_t<decltype([]() {
|
||||
if constexpr (count == 0) {
|
||||
return std::add_pointer_t<TTmpl<TFirst, TArgs...>>(nullptr);
|
||||
}
|
||||
else {
|
||||
auto wrapper = []<typename... TArgsInner>(std::tuple<TArgsInner...>*)
|
||||
{
|
||||
return static_cast<std::tuple<TFirst, TArgsInner...>*>(nullptr);
|
||||
};
|
||||
return wrapper(static_cast<base_t*>(nullptr));
|
||||
return std::add_pointer_t<typename drop_types<TTmpl<TArgs...>, count-1>::type>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
using type_t = std::remove_pointer_t<decltype(makeTypeHelper())>;
|
||||
}())>;
|
||||
};
|
||||
|
||||
template<template<typename> typename TFilter, typename... TArgs>
|
||||
auto typeFilterHelper(std::tuple<TArgs...>*)
|
||||
template<template<typename...> typename TTmpl>
|
||||
struct drop_types<TTmpl<>, 0>
|
||||
{
|
||||
return static_cast<typename TypeFilter<TFilter, TArgs...>::type_t*>(nullptr);
|
||||
}
|
||||
using type = TTmpl<>;
|
||||
};
|
||||
|
||||
template<template<typename> typename TFilter, typename TTuple>
|
||||
using filter_types_t = std::remove_pointer_t<decltype(typeFilterHelper<TFilter>(static_cast<TTuple*>(nullptr)))>;
|
||||
template<typename TTmpl, std::size_t count = 1>
|
||||
using drop_types_t = typename drop_types<TTmpl, count>::type;
|
||||
|
||||
template<typename TTmpl, std::size_t count = 1>
|
||||
struct crop_types;
|
||||
|
||||
template<template<typename...> typename TTmpl, std::size_t count, typename TFirst, typename... TArgs>
|
||||
struct crop_types<TTmpl<TFirst, TArgs...>, count>
|
||||
{
|
||||
using type = std::remove_pointer_t<decltype([]() {
|
||||
if constexpr (count == 0) {
|
||||
return std::add_pointer_t<TTmpl<>>(nullptr);
|
||||
}
|
||||
else {
|
||||
return std::add_pointer_t<prepend_type_t<typename crop_types<TTmpl<TArgs...>, count-1>::type, TFirst>>(nullptr);
|
||||
}
|
||||
}())>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename TTmpl>
|
||||
struct crop_types<TTmpl<>, 0>
|
||||
{
|
||||
using type = TTmpl<>;
|
||||
};
|
||||
|
||||
template<typename TTmpl, std::size_t count = 1>
|
||||
using crop_types_t = typename crop_types<TTmpl, count>::type;
|
||||
|
||||
template<typename TTmpl, std::size_t idx, typename... TTypes>
|
||||
struct insert_type;
|
||||
|
||||
template<template<typename> typename TTmpl, std::size_t idx, typename... TTypes, typename... TArgs>
|
||||
struct insert_type<TTmpl<TArgs...>, idx, TTypes...>
|
||||
{
|
||||
using type = concat_types_t<crop_types_t<TTmpl<TArgs...>, idx>, TTmpl<TTypes...>, drop_types_t<TTmpl<TArgs...>, idx>>;
|
||||
};
|
||||
|
||||
template<typename TTmpl, std::size_t idx, typename... TTypes>
|
||||
using insert_type_t = typename insert_type<TTmpl, idx, TTypes...>::type;
|
||||
|
||||
template<template<typename...> typename TFilter, typename... TFilterArgs>
|
||||
struct TypeFilter;
|
||||
|
||||
template<template<typename...> typename TFilter, typename TFirstFilterArg, typename... TFilterArgs>
|
||||
struct TypeFilter<TFilter, TFirstFilterArg, TFilterArgs...>
|
||||
{
|
||||
using filter_t = TFilter<TFirstFilterArg, TFilterArgs...>;
|
||||
template<typename... TTypes>
|
||||
struct Inner
|
||||
{
|
||||
using type_t = std::remove_pointer_t<decltype([]() {
|
||||
if constexpr (sizeof...(TTypes) == 0) {
|
||||
return (std::tuple<>*)(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
using base_t = drop_types_t<Inner<TTypes...>>;
|
||||
using current_t = type_at_t<0, TTypes...>;
|
||||
using inner_filter_t = replace_typevars_t<filter_t, current_t>;
|
||||
if constexpr (inner_filter_t::value) {
|
||||
return std::add_pointer_t<typename base_t::type_t>(nullptr);
|
||||
}
|
||||
else {
|
||||
return std::add_pointer_t<prepend_type_t<typename base_t::type_t, current_t>>(nullptr);
|
||||
}
|
||||
}
|
||||
}())>;
|
||||
};
|
||||
|
||||
template<typename TTuple>
|
||||
using type = typename copy_args_t<TTuple, Inner>::type_t;
|
||||
};
|
||||
|
||||
template<template<typename...> typename TFilter>
|
||||
struct TypeFilter<TFilter>
|
||||
{
|
||||
template<typename TTuple>
|
||||
using type = typename TypeFilter<TFilter, TypeVar<>>::template type<TTuple>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename TFilter, typename TTuple, typename... TFilterArgs>
|
||||
using remove_type_if_t = typename TypeFilter<TFilter, TFilterArgs...>::template type<TTuple>;
|
||||
|
||||
template<auto func, typename TTuple, typename... TFilterArgs>
|
||||
using remove_type_if_fn_t = remove_type_if_t<type_func<func>::template type, TTuple, TFilterArgs...>;
|
||||
|
||||
template<typename TWhat, typename TTuple>
|
||||
using remove_type_t = remove_type_if_t<std::is_same, TTuple, TWhat, TypeVar<>>;// remove_type_if_fn_t<[](auto type) { return type == Type<TWhat>(); }, std::tuple<TArgs...>>;
|
||||
|
||||
template<template<typename> typename TPredicate, typename... TArgs>
|
||||
auto mapTypesHelper(std::tuple<TArgs...>)
|
||||
@@ -105,7 +323,7 @@ template<template<typename...> typename TTemplate, typename... TArgs>
|
||||
struct is_template_instance<TTemplate, TTemplate<TArgs...>> : std::true_type {};
|
||||
|
||||
template<template<typename...> typename TTemplate, typename TType>
|
||||
constexpr bool is_template_instance_v = is_template_instance<TTemplate, TType>::value;
|
||||
inline constexpr bool is_template_instance_v = is_template_instance<TTemplate, TType>::value;
|
||||
|
||||
namespace impl
|
||||
{
|
||||
@@ -137,7 +355,7 @@ template<template<typename...> typename TTemplate, typename TType, typename... T
|
||||
struct match_template_type<TTemplate<TArgs...>, TType> : impl::tmpl_param_comparator<TTemplate, TArgs...>::template matches_t<TType> {};
|
||||
|
||||
template<typename TTemplate, typename TType>
|
||||
constexpr bool match_template_type_v = match_template_type<TTemplate, TType>::value;
|
||||
inline constexpr bool match_template_type_v = match_template_type<TTemplate, TType>::value;
|
||||
|
||||
// similar to std::is_same, but allows placeholders
|
||||
// - is_type_or_impl<some_tmpl<Type_>, some_type> resolves to some_tmpl<some_type>
|
||||
@@ -176,7 +394,7 @@ template<typename TConcrete, typename... TMatches>
|
||||
struct match_any_type : std::disjunction<type_matches_t<TMatches, TConcrete>...> {};
|
||||
|
||||
template<typename TConcrete, typename... TMatches>
|
||||
static constexpr bool match_any_type_v = match_any_type<TConcrete, TMatches...>::value;
|
||||
inline constexpr bool match_any_type_v = match_any_type<TConcrete, TMatches...>::value;
|
||||
|
||||
template<typename T, typename... Types>
|
||||
concept union_type = match_any_type_v<T, Types...>;
|
||||
@@ -190,7 +408,7 @@ struct is_type_member<TElement, TCollection<Ts...>>
|
||||
{};
|
||||
|
||||
template<typename TElement, typename TCollection>
|
||||
constexpr bool is_type_member_v = is_type_member<TElement, TCollection>::value;
|
||||
inline constexpr bool is_type_member_v = is_type_member<TElement, TCollection>::value;
|
||||
|
||||
template<typename T, typename TObject>
|
||||
struct is_member_object_pointer_of : std::false_type {};
|
||||
@@ -216,21 +434,6 @@ using copy_cv_t = copy_const_t<TFrom, copy_volatile_t<TFrom, TTo>>;
|
||||
template<typename TActual, typename TDelay>
|
||||
using delay_type_t = TActual;
|
||||
|
||||
|
||||
template<std::size_t I, typename TArg, typename... TArgs>
|
||||
struct TypeAtHelper
|
||||
{
|
||||
using type_t = typename TypeAtHelper<I-1, TArgs...>::type_t;
|
||||
};
|
||||
|
||||
template<typename TArg, typename... TArgs>
|
||||
struct TypeAtHelper<0, TArg, TArgs...>
|
||||
{
|
||||
using type_t = TArg;
|
||||
};
|
||||
template<std::size_t I, typename... TArgs>
|
||||
using type_at_t = TypeAtHelper<I, TArgs...>::type_t;
|
||||
|
||||
template<typename TDefault, template<typename...> typename TOper, typename... TArgs>
|
||||
struct detect_or
|
||||
{
|
||||
@@ -248,6 +451,10 @@ struct detect_or<TDefault, TOper, TArgs...>
|
||||
template<typename TDefault, template<typename...> typename TOper, typename... TArgs>
|
||||
using detect_or_t = detect_or<TDefault, TOper, TArgs...>::type;
|
||||
|
||||
|
||||
template<template<typename...> typename TOper, typename... TArgs>
|
||||
inline constexpr bool detected_v = detect_or<void, TOper, TArgs...>::detected;
|
||||
|
||||
struct empty_type {};
|
||||
|
||||
template<typename T, bool enable>
|
||||
@@ -279,6 +486,25 @@ decltype(auto) delayEvaluation(TType&& value)
|
||||
#if MIJIN_STATIC_TESTS
|
||||
namespace test
|
||||
{
|
||||
static_assert(std::is_same_v<concat_types_t<std::tuple<int, double>, std::tuple<bool, float>>, std::tuple<int, double, bool, float>>);
|
||||
static_assert(std::is_same_v<concat_types_t<std::tuple<int, double>, std::tuple<>>, std::tuple<int, double>>);
|
||||
static_assert(std::is_same_v<concat_types_t<std::tuple<int, double>>, std::tuple<int, double>>);
|
||||
|
||||
static_assert(std::is_same_v<drop_types_t<std::tuple<int, double, bool>, 0>, std::tuple<int, double, bool>>);
|
||||
static_assert(std::is_same_v<drop_types_t<std::tuple<int, double, bool>, 1>, std::tuple<double, bool>>);
|
||||
static_assert(std::is_same_v<drop_types_t<std::tuple<int, double, bool>, 2>, std::tuple<bool>>);
|
||||
static_assert(std::is_same_v<drop_types_t<std::tuple<int, double, bool>, 3>, std::tuple<>>);
|
||||
|
||||
static_assert(std::is_same_v<crop_types_t<std::tuple<int, double, bool>, 0>, std::tuple<>>);
|
||||
static_assert(std::is_same_v<crop_types_t<std::tuple<int, double, bool>, 1>, std::tuple<int>>);
|
||||
static_assert(std::is_same_v<crop_types_t<std::tuple<int, double, bool>, 2>, std::tuple<int, double>>);
|
||||
static_assert(std::is_same_v<crop_types_t<std::tuple<int, double, bool>, 3>, std::tuple<int, double, bool>>);
|
||||
|
||||
static_assert(std::is_same_v<insert_type_t<std::tuple<int, bool>, 1, double>, std::tuple<int, double, bool>>);
|
||||
static_assert(std::is_same_v<insert_type_t<std::tuple<int, bool>, 1, double, float>, std::tuple<int, double, float, bool>>);
|
||||
static_assert(std::is_same_v<insert_type_t<std::tuple<int, bool>, 0, double>, std::tuple<double, int, bool>>);
|
||||
static_assert(std::is_same_v<insert_type_t<std::tuple<int, bool>, 2, double>, std::tuple<int, bool, double>>);
|
||||
|
||||
template<typename T, typename U>
|
||||
struct MyTemplate {};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user