#pragma once #if !defined(MIJIN_UTIL_TRAITS_HPP_INCLUDED) #define MIJIN_UTIL_TRAITS_HPP_INCLUDED 1 #include namespace mijin { // // public defines // // // public constants // // // public types // struct Type_; // use as typevar struct Any_; // use as placeholder in templates template struct always_false { static constexpr bool value = false; }; template inline constexpr bool always_false_v = always_false::value; template struct always_false_val { static constexpr bool value = false; }; template inline constexpr bool always_false_val_v = always_false_val::value; template typename TFilter, typename... TArgs> struct TypeFilter; template typename TFilter> struct TypeFilter { using type_t = std::tuple<>; }; template typename TFilter, typename TFirst, typename... TArgs> struct TypeFilter { static consteval auto makeTypeHelper() { using base_t = typename TypeFilter::type_t; // note: not using decltype, as the compiler might think it is being evaluated if constexpr (!TFilter::value) { return static_cast(nullptr); } else { auto wrapper = [](std::tuple*) { return static_cast*>(nullptr); }; return wrapper(static_cast(nullptr)); } } using type_t = std::remove_pointer_t; }; template typename TFilter, typename... TArgs> auto typeFilterHelper(std::tuple*) { return static_cast::type_t*>(nullptr); } template typename TFilter, typename TTuple> using filter_types_t = std::remove_pointer_t(static_cast(nullptr)))>; template typename TPredicate, typename... TArgs> auto mapTypesHelper(std::tuple) { return static_cast...>*>(nullptr); } template typename TPredicate, typename TTuple> using map_types_t = std::remove_pointer_t(std::declval()))>; template typename TPredicate, template typename TTemplate> struct map_template { template using type_t = TTemplate>; }; template typename TTemplate, typename TType> struct is_template_instance : std::false_type {}; 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; namespace impl { template typename TTemplate, typename... TArgsTTmpl> struct tmpl_param_comparator { template static constexpr bool compare_single = std::is_same_v or std::is_same_v; template struct matches : std::false_type {}; // original (which MSVC didn't like for some reason :/) // template // struct matches> : std::bool_constant<(compare_single && ...)> {}; template typename TOtherTemplate, typename... TArgsInstance> requires(is_template_instance_v>) struct matches> : std::bool_constant<(compare_single && ...)> {}; template using matches_t = matches; }; } template struct match_template_type : std::false_type {}; template typename TTemplate, typename TType, typename... TArgs> struct match_template_type, TType> : impl::tmpl_param_comparator::template matches_t {}; template 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 // - is_type_or_impl, some_type> checks if some_type is an instance of some_tmpl with int as 2nd parameter template struct type_matches { using type = std::is_same; }; template typename TTmplMatch, typename TConcrete> struct type_matches, TConcrete> { using type = TTmplMatch; }; template typename TTmplMatch, typename TConcrete, typename... TArgs> struct type_matches, TConcrete> { using type = match_template_type, TConcrete>; }; template using type_matches_t = type_matches::type; template inline constexpr bool type_matches_v = type_matches_t::value; template struct is_any_type : std::disjunction...> {}; template static constexpr bool is_any_type_v = is_any_type::value; template struct match_any_type : std::disjunction...> {}; template static constexpr bool match_any_type_v = match_any_type::value; template concept union_type = match_any_type_v; template struct is_type_member; template typename TCollection, typename... Ts> struct is_type_member> : std::bool_constant<(... || std::is_same{})> {}; template constexpr bool is_type_member_v = is_type_member::value; template struct is_member_object_pointer_of : std::false_type {}; template struct is_member_object_pointer_of : std::true_type {}; template inline constexpr bool is_member_object_pointer_of_v = is_member_object_pointer_of::value; template concept member_object_pointer_of = is_member_object_pointer_of_v; template using copy_const_t = std::conditional_t, std::add_const_t, std::remove_const_t>; template using copy_volatile_t = std::conditional_t, std::add_volatile_t, std::remove_volatile_t>; template 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 { using type = TDefault; static constexpr bool detected = false; }; template typename TOper, typename... TArgs> requires requires { typename TOper; } struct detect_or { using type = TOper; static constexpr bool detected = true; }; template typename TOper, typename... TArgs> using detect_or_t = detect_or::type; struct empty_type {}; template struct optional_base { using type = T; }; template struct optional_base { using type = empty_type; }; template using optional_base_t = optional_base::type; // // public functions // template decltype(auto) delayEvaluation(TType&& value) { return static_cast(value); } #define MIJIN_STATIC_TESTS 1 #if MIJIN_STATIC_TESTS namespace test { template struct MyTemplate {}; static_assert(match_template_type_v, MyTemplate>); static_assert(match_template_type_v, MyTemplate>); static_assert(type_matches_v, MyTemplate>); static_assert(type_matches_v, MyTemplate>); static_assert(!type_matches_v, MyTemplate>); static_assert(type_matches_v, MyTemplate>); static_assert(type_matches_v, void*>); static_assert(union_type); static_assert(!union_type); static_assert(!union_type); static_assert(union_type, MyTemplate>); static_assert(union_type, MyTemplate>); static_assert(union_type, MyTemplate>); static_assert(union_type, MyTemplate, MyTemplate>); static_assert(!union_type); static_assert(union_type>); static_assert(!union_type>); } #endif } // namespace mijin #endif // !defined(MIJIN_UTIL_TRAITS_HPP_INCLUDED)