From 1bb64f04739725cc1e36f137df4a2ea6358ee358 Mon Sep 17 00:00:00 2001
From: Patrick Wuttke
Date: Tue, 17 Feb 2026 10:24:34 +0100
Subject: [PATCH] Added utility functions for modifying type argument lists.
---
source/mijin/util/traits.hpp | 320 ++++++++++++++++++++++++++++++-----
1 file changed, 273 insertions(+), 47 deletions(-)
diff --git a/source/mijin/util/traits.hpp b/source/mijin/util/traits.hpp
index 5a8ce3d..0a57fe7 100644
--- a/source/mijin/util/traits.hpp
+++ b/source/mijin/util/traits.hpp
@@ -4,7 +4,9 @@
#if !defined(MIJIN_UTIL_TRAITS_HPP_INCLUDED)
#define MIJIN_UTIL_TRAITS_HPP_INCLUDED 1
+#include
#include
+#include
namespace mijin
{
@@ -24,6 +26,61 @@ namespace mijin
struct Type_; // use as typevar
struct Any_; // use as placeholder in templates
+template
+struct TypeVar {};
+
+template
+struct Type
+{
+ using type_t = T;
+
+ template
+ constexpr bool operator==(Type) const noexcept
+ {
+ return std::is_same_v;
+ }
+
+ template
+ constexpr bool operator!=(Type) const noexcept
+ {
+ return !std::is_same_v;
+ }
+};
+
+template
+struct type_func
+{
+ template
+ static constexpr auto value = func(Type()...);
+
+ template
+ struct type {
+ static constexpr auto value = func(Type()...);
+ };
+};
+
+template
+struct value_list
+{
+ template
+ static constexpr auto apply(TFunc&& func)
+ {
+ return std::invoke(std::forward(func), Values...);
+ }
+
+ template
+ static constexpr void forEach(TFunc func)
+ {
+ (std::invoke(func, Values), ...);
+ }
+
+ template
+ static constexpr void forEachStatic(TFunc func)
+ {
+ (std::invoke(func, std::integral_constant, Values>()), ...);
+ }
+};
+
template
struct always_false
{
@@ -42,46 +99,207 @@ struct always_false_val
template
inline constexpr bool always_false_val_v = always_false_val::value;
-template typename TFilter, typename... TArgs>
-struct TypeFilter;
-
-template typename TFilter>
-struct TypeFilter
+template
+struct TypeAtHelper
{
- using type_t = std::tuple<>;
+ using type_t = typename TypeAtHelper::type_t;
};
-template typename TFilter, typename TFirst, typename... TArgs>
-struct TypeFilter
+template
+struct TypeAtHelper<0, TArg, TArgs...>
{
- static consteval auto makeTypeHelper()
- {
- using base_t = typename TypeFilter::type_t;
+ using type_t = TArg;
+};
+template
+using type_at_t = typename TypeAtHelper::type_t;
- // note: not using decltype, as the compiler might think it is being evaluated
- if constexpr (!TFilter::value) {
- return static_cast(nullptr);
+template typename TTo>
+struct copy_args;
+
+template typename TFrom, template typename TTo, typename... TArgs>
+struct copy_args, TTo> {
+ using type = TTo;
+};
+
+template typename TTo>
+using copy_args_t = typename copy_args::type;
+
+template
+struct replace_type;
+
+template typename TTmpl, typename TFrom, typename TTo, typename... TArgs>
+struct replace_type, TFrom, TTo>
+{
+ using type = TTmpl, TTo, TArgs>...>;
+};
+
+template
+using replace_type_t = typename replace_type::type;
+
+template
+struct ReplaceTypevarsHelper;
+
+template
+struct ReplaceTypevarsHelper
+{
+ using type = replace_type_t::type, TypeVar, TFirst>;
+};
+
+template
+struct ReplaceTypevarsHelper
+{
+ using type = TTmpl;
+};
+
+template
+using replace_typevars_t = typename ReplaceTypevarsHelper::type;
+
+template
+struct prepend_type;
+
+template typename TTmpl, typename TType, typename... TArgs>
+struct prepend_type, TType>
+{
+ using type = TTmpl;
+};
+
+template
+using prepend_type_t = typename prepend_type::type;
+
+template
+struct concat_types;
+
+template typename TTmplA, template typename TTmplB, typename... TArgsA, typename... TArgsB>
+struct concat_types, TTmplB>
+{
+ using type = TTmplA;
+};
+
+template
+struct concat_types
+{
+ using type = typename concat_types::type, TMore...>::type;
+};
+
+template
+struct concat_types
+{
+ using type = TTmpl;
+};
+
+template
+using concat_types_t = typename concat_types::type;
+
+template
+struct drop_types;
+
+template typename TTmpl, std::size_t count, typename TFirst, typename... TArgs>
+struct drop_types, count>
+{
+ using type = std::remove_pointer_t>(nullptr);
}
else {
- auto wrapper = [](std::tuple*)
- {
- return static_cast*>(nullptr);
- };
- return wrapper(static_cast(nullptr));
+ return std::add_pointer_t, count-1>::type>(nullptr);
}
- }
-
- using type_t = std::remove_pointer_t;
+ }())>;
};
-template typename TFilter, typename... TArgs>
-auto typeFilterHelper(std::tuple*)
+template typename TTmpl>
+struct drop_types, 0>
{
- return static_cast::type_t*>(nullptr);
-}
+ using type = TTmpl<>;
+};
-template typename TFilter, typename TTuple>
-using filter_types_t = std::remove_pointer_t(static_cast(nullptr)))>;
+template
+using drop_types_t = typename drop_types::type;
+
+template
+struct crop_types;
+
+template typename TTmpl, std::size_t count, typename TFirst, typename... TArgs>
+struct crop_types, count>
+{
+ using type = std::remove_pointer_t>(nullptr);
+ }
+ else {
+ return std::add_pointer_t, count-1>::type, TFirst>>(nullptr);
+ }
+ }())>;
+};
+
+template typename TTmpl>
+struct crop_types, 0>
+{
+ using type = TTmpl<>;
+};
+
+template
+using crop_types_t = typename crop_types::type;
+
+template
+struct insert_type;
+
+template typename TTmpl, std::size_t idx, typename... TTypes, typename... TArgs>
+struct insert_type, idx, TTypes...>
+{
+ using type = concat_types_t, idx>, TTmpl, drop_types_t, idx>>;
+};
+
+template
+using insert_type_t = typename insert_type::type;
+
+template typename TFilter, typename... TFilterArgs>
+struct TypeFilter;
+
+template typename TFilter, typename TFirstFilterArg, typename... TFilterArgs>
+struct TypeFilter
+{
+ using filter_t = TFilter;
+ template
+ struct Inner
+ {
+ using type_t = std::remove_pointer_t*)(nullptr);
+ }
+ else
+ {
+ using base_t = drop_types_t>;
+ using current_t = type_at_t<0, TTypes...>;
+ using inner_filter_t = replace_typevars_t;
+ if constexpr (inner_filter_t::value) {
+ return std::add_pointer_t(nullptr);
+ }
+ else {
+ return std::add_pointer_t>(nullptr);
+ }
+ }
+ }())>;
+ };
+
+ template
+ using type = typename copy_args_t::type_t;
+};
+
+template typename TFilter>
+struct TypeFilter
+{
+ template
+ using type = typename TypeFilter>::template type;
+};
+
+template typename TFilter, typename TTuple, typename... TFilterArgs>
+using remove_type_if_t = typename TypeFilter::template type;
+
+template
+using remove_type_if_fn_t = remove_type_if_t::template type, TTuple, TFilterArgs...>;
+
+template
+using remove_type_t = remove_type_if_t>;// remove_type_if_fn_t<[](auto type) { return type == Type(); }, std::tuple>;
template typename TPredicate, typename... TArgs>
auto mapTypesHelper(std::tuple)
@@ -105,7 +323,7 @@ template typename TTemplate, typename... TArgs>
struct is_template_instance> : std::true_type {};
template typename TTemplate, typename TType>
-constexpr bool is_template_instance_v = is_template_instance::value;
+inline constexpr bool is_template_instance_v = is_template_instance::value;
namespace impl
{
@@ -137,7 +355,7 @@ template typename TTemplate, typename TType, typename... T
struct match_template_type, TType> : impl::tmpl_param_comparator::template matches_t {};
template
-constexpr bool match_template_type_v = match_template_type::value;
+inline constexpr bool match_template_type_v = match_template_type::value;
// similar to std::is_same, but allows placeholders
// - is_type_or_impl, some_type> resolves to some_tmpl
@@ -176,7 +394,7 @@ template
struct match_any_type : std::disjunction...> {};
template
-static constexpr bool match_any_type_v = match_any_type::value;
+inline constexpr bool match_any_type_v = match_any_type::value;
template
concept union_type = match_any_type_v;
@@ -190,7 +408,7 @@ struct is_type_member>
{};
template
-constexpr bool is_type_member_v = is_type_member::value;
+inline constexpr bool is_type_member_v = is_type_member::value;
template
struct is_member_object_pointer_of : std::false_type {};
@@ -216,21 +434,6 @@ using copy_cv_t = copy_const_t>;
template
using delay_type_t = TActual;
-
-template
-struct TypeAtHelper
-{
- using type_t = typename TypeAtHelper::type_t;
-};
-
-template
-struct TypeAtHelper<0, TArg, TArgs...>
-{
- using type_t = TArg;
-};
-template
-using type_at_t = TypeAtHelper::type_t;
-
template typename TOper, typename... TArgs>
struct detect_or
{
@@ -248,6 +451,10 @@ struct detect_or
template typename TOper, typename... TArgs>
using detect_or_t = detect_or::type;
+
+template typename TOper, typename... TArgs>
+inline constexpr bool detected_v = detect_or::detected;
+
struct empty_type {};
template
@@ -279,6 +486,25 @@ decltype(auto) delayEvaluation(TType&& value)
#if MIJIN_STATIC_TESTS
namespace test
{
+static_assert(std::is_same_v, std::tuple>, std::tuple>);
+static_assert(std::is_same_v, std::tuple<>>, std::tuple>);
+static_assert(std::is_same_v>, std::tuple>);
+
+static_assert(std::is_same_v, 0>, std::tuple>);
+static_assert(std::is_same_v, 1>, std::tuple>);
+static_assert(std::is_same_v, 2>, std::tuple>);
+static_assert(std::is_same_v, 3>, std::tuple<>>);
+
+static_assert(std::is_same_v, 0>, std::tuple<>>);
+static_assert(std::is_same_v, 1>, std::tuple>);
+static_assert(std::is_same_v, 2>, std::tuple>);
+static_assert(std::is_same_v, 3>, std::tuple>);
+
+static_assert(std::is_same_v, 1, double>, std::tuple>);
+static_assert(std::is_same_v, 1, double, float>, std::tuple>);
+static_assert(std::is_same_v, 0, double>, std::tuple>);
+static_assert(std::is_same_v, 2, double>, std::tuple>);
+
template
struct MyTemplate {};