Added utility functions for modifying type argument lists.

This commit is contained in:
Patrick Wuttke
2026-02-17 10:24:34 +01:00
parent 3d9d62f3e3
commit 1bb64f0473

View File

@@ -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 {};