use concepts instead of std::enable_if

This commit is contained in:
oltolm 2025-01-03 11:00:18 +01:00 committed by Elad
parent 5e6aef5dfd
commit ebde5310b9
21 changed files with 206 additions and 134 deletions

View file

@ -256,7 +256,7 @@ struct ff_t : bf_base<T, N>
#endif
template <typename T, uint I, uint N>
struct fmt_unveil<bf_t<T, I, N>, void>
struct fmt_unveil<bf_t<T, I, N>>
{
using type = typename fmt_unveil<std::common_type_t<T>>::type;
@ -267,7 +267,7 @@ struct fmt_unveil<bf_t<T, I, N>, void>
};
template <typename F, typename... Fields>
struct fmt_unveil<cf_t<F, Fields...>, void>
struct fmt_unveil<cf_t<F, Fields...>>
{
using type = typename fmt_unveil<std::common_type_t<typename F::type>>::type;
@ -278,7 +278,7 @@ struct fmt_unveil<cf_t<F, Fields...>, void>
};
template <typename T, T V, uint N>
struct fmt_unveil<ff_t<T, V, N>, void>
struct fmt_unveil<ff_t<T, V, N>>
{
using type = typename fmt_unveil<std::common_type_t<T>>::type;

View file

@ -22,7 +22,7 @@ namespace fmt
#endif
}
template <typename T, typename = void>
template <typename T>
struct fmt_unveil
{
static_assert(sizeof(T) > 0, "fmt_unveil<> error: incomplete type");
@ -54,7 +54,8 @@ struct fmt_unveil
};
template <typename T>
struct fmt_unveil<T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) <= 8 && alignof(T) <= 8>>
requires(std::is_integral_v<T> && sizeof(T) <= 8 && alignof(T) <= 8)
struct fmt_unveil<T>
{
using type = T;
@ -65,7 +66,8 @@ struct fmt_unveil<T, std::enable_if_t<std::is_integral_v<T> && sizeof(T) <= 8 &&
};
template <typename T>
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point_v<T> && sizeof(T) <= 8 && alignof(T) <= 8>>
requires(std::is_floating_point_v<T> && sizeof(T) <= 8 && alignof(T) <= 8)
struct fmt_unveil<T>
{
using type = T;
@ -77,7 +79,8 @@ struct fmt_unveil<T, std::enable_if_t<std::is_floating_point_v<T> && sizeof(T) <
};
template <typename T>
struct fmt_unveil<T, std::enable_if_t<std::is_enum_v<T>>>
requires std::is_enum_v<T>
struct fmt_unveil<T>
{
using type = T;
@ -88,7 +91,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_enum_v<T>>>
};
template <typename T>
struct fmt_unveil<T*, void>
struct fmt_unveil<T*>
{
using type = std::add_const_t<T>*;
@ -105,7 +108,7 @@ namespace fmt
}
template <fmt::CharT T, usz N>
struct fmt_unveil<T[N], void>
struct fmt_unveil<T[N]>
{
using type = std::add_const_t<T>*;
@ -116,7 +119,7 @@ struct fmt_unveil<T[N], void>
};
template <typename T, bool Se, usz Align>
struct fmt_unveil<se_t<T, Se, Align>, void>
struct fmt_unveil<se_t<T, Se, Align>>
{
using type = typename fmt_unveil<T>::type;
@ -200,13 +203,13 @@ struct fmt_class_string
};
template <>
struct fmt_class_string<const void*, void>
struct fmt_class_string<const void*>
{
static void format(std::string& out, u64 arg);
};
template <typename T>
struct fmt_class_string<T*, void> : fmt_class_string<const void*, void>
struct fmt_class_string<T*> : fmt_class_string<const void*>
{
// Classify all pointers as const void*
};
@ -218,18 +221,18 @@ struct fmt_class_string<const char*, void>
};
template <>
struct fmt_class_string<char*, void> : fmt_class_string<const char*>
struct fmt_class_string<char*> : fmt_class_string<const char*>
{
// Classify char* as const char*
};
template <>
struct fmt_class_string<const char8_t*, void> : fmt_class_string<const char*>
struct fmt_class_string<const char8_t*> : fmt_class_string<const char*>
{
};
template <>
struct fmt_class_string<char8_t*, void> : fmt_class_string<const char8_t*>
struct fmt_class_string<char8_t*> : fmt_class_string<const char8_t*>
{
};
@ -240,7 +243,7 @@ struct fmt_class_string<const wchar_t*, void>
};
template <>
struct fmt_class_string<wchar_t*, void> : fmt_class_string<const wchar_t*>
struct fmt_class_string<wchar_t*> : fmt_class_string<const wchar_t*>
{
};

View file

@ -385,7 +385,7 @@ public:
};
template <typename T>
struct fmt_unveil<bs_t<T>, void>
struct fmt_unveil<bs_t<T>>
{
// Format as is
using type = bs_t<T>;

View file

@ -110,7 +110,8 @@ protected:
virtual u32 DisAsmBranchTarget(s32 /*imm*/);
// TODO: Add builtin fmt helpper for best performance
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template <typename T>
requires std::is_integral_v<T>
static std::string SignedHex(T value)
{
const auto v = static_cast<std::make_signed_t<T>>(value);

View file

@ -2,6 +2,12 @@
#ifdef LLVM_AVAILABLE
#include "util/types.hpp"
#include "util/sysinfo.hpp"
#include "Utilities/StrFmt.h"
#include "Utilities/JIT.h"
#include "util/v128.hpp"
#ifdef _MSC_VER
#pragma warning(push, 0)
#else
@ -24,7 +30,9 @@
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IntrinsicsX86.h"
#ifdef ARCH_ARM64
#include "llvm/IR/IntrinsicsAArch64.h"
#endif
#include "llvm/IR/InlineAsm.h"
#ifdef _MSC_VER
@ -33,12 +41,6 @@
#pragma GCC diagnostic pop
#endif
#include "util/types.hpp"
#include "util/sysinfo.hpp"
#include "Utilities/StrFmt.h"
#include "Utilities/JIT.h"
#include "util/v128.hpp"
#include <functional>
#include <unordered_map>
@ -60,9 +62,8 @@ template <typename T>
concept LLVMValue = (std::is_pointer_v<T>) && (std::is_base_of_v<llvm::Value, std::remove_pointer_t<T>>);
template <typename T>
concept DSLValue = requires (T& v)
{
{ v.eval(std::declval<llvm::IRBuilder<>*>()) } -> LLVMValue;
concept DSLValue = requires(T& v, llvm::IRBuilder<>* ir) {
{ v.eval(ir) } -> LLVMValue;
};
template <usz N>
@ -476,31 +477,33 @@ struct llvm_value_t<T[N]> : llvm_value_t<std::conditional_t<(std::extent_v<T> >
template <typename T>
using llvm_expr_t = std::decay_t<T>;
template <typename T, typename = void>
template <typename T>
struct is_llvm_expr
{
};
template <typename T>
struct is_llvm_expr<T, std::void_t<decltype(std::declval<T>().eval(std::declval<llvm::IRBuilder<>*>()))>>
template <DSLValue T>
struct is_llvm_expr<T>
{
using type = typename std::decay_t<T>::type;
};
template <typename T, typename Of, typename = void>
template <typename T, typename Of>
struct is_llvm_expr_of
{
static constexpr bool ok = false;
};
template <typename T, typename Of>
struct is_llvm_expr_of<T, Of, std::void_t<typename is_llvm_expr<T>::type, typename is_llvm_expr<Of>::type>>
requires(requires { typename is_llvm_expr<T>::type; } && requires { typename is_llvm_expr<Of>::type; })
struct is_llvm_expr_of<T, Of>
{
static constexpr bool ok = std::is_same_v<typename is_llvm_expr<T>::type, typename is_llvm_expr<Of>::type>;
};
template <typename T, typename... Types>
using llvm_common_t = std::enable_if_t<(is_llvm_expr_of<T, Types>::ok && ...), typename is_llvm_expr<T>::type>;
requires(is_llvm_expr_of<T, Types>::ok && ...)
using llvm_common_t = typename is_llvm_expr<T>::type;
template <typename... Args>
using llvm_match_tuple = decltype(std::tuple_cat(std::declval<llvm_expr_t<Args>&>().match(std::declval<llvm::Value*&>(), nullptr)...));
@ -1606,7 +1609,8 @@ struct llvm_ord
};
template <typename T>
llvm_ord(T&&) -> llvm_ord<std::enable_if_t<is_llvm_cmp<std::decay_t<T>>::value, T&&>>;
requires is_llvm_cmp<std::decay_t<T>>::value
llvm_ord(T&&) -> llvm_ord<T&&>;
template <typename Cmp, typename T = llvm_common_t<Cmp>>
struct llvm_uno
@ -1659,7 +1663,8 @@ struct llvm_uno
};
template <typename T>
llvm_uno(T&&) -> llvm_uno<std::enable_if_t<is_llvm_cmp<std::decay_t<T>>::value, T&&>>;
requires is_llvm_cmp<std::decay_t<T>>::value
llvm_uno(T&&) -> llvm_uno<T&&>;
template <typename T1, typename T2>
inline llvm_cmp<T1, T2, llvm::ICmpInst::ICMP_EQ> operator ==(T1&& a1, T2&& a2)
@ -3020,7 +3025,7 @@ struct llvm_calli
if (((std::get<I>(r) = std::get<I>(a).match(v[I], _m), v[I]) && ...))
{
return std::tuple_cat(std::get<I>(r)...);
}
}
}
}
}
@ -3194,14 +3199,16 @@ public:
return {};
}
template <typename T, typename = llvm_common_t<T>>
template <typename T>
requires requires { typename llvm_common_t<T>; }
static auto match_expr(llvm::Value* v, llvm::Module* _m, T&& expr)
{
auto r = expr.match(v, _m);
return std::tuple_cat(std::make_tuple(v != nullptr), r);
}
template <typename T, typename U, typename = llvm_common_t<T, U>>
template <typename T, typename U>
requires requires { typename llvm_common_t<T, U>; }
auto match_expr(T&& arg, U&& expr) -> decltype(std::tuple_cat(std::make_tuple(false), expr.match(std::declval<llvm::Value*&>(), nullptr)))
{
auto v = arg.eval(m_ir);
@ -3236,202 +3243,235 @@ public:
return expr_t<T, F>{std::forward<T>(expr), std::move(matcher)};
}
template <typename T, typename = std::enable_if_t<is_llvm_cmp<std::decay_t<T>>::value>>
template <typename T>
requires is_llvm_cmp<std::decay_t<T>>::value
static auto fcmp_ord(T&& cmp_expr)
{
return llvm_ord{std::forward<T>(cmp_expr)};
}
template <typename T, typename = std::enable_if_t<is_llvm_cmp<std::decay_t<T>>::value>>
template <typename T>
requires is_llvm_cmp<std::decay_t<T>>::value
static auto fcmp_uno(T&& cmp_expr)
{
return llvm_uno{std::forward<T>(cmp_expr)};
}
template <typename U, typename T, typename = std::enable_if_t<llvm_noncast<U, T>::is_ok>>
template <typename U, typename T>
requires llvm_noncast<U, T>::is_ok
static auto noncast(T&& expr)
{
return llvm_noncast<U, T>{std::forward<T>(expr)};
}
template <typename U, typename T, typename = std::enable_if_t<llvm_bitcast<U, T>::is_ok>>
template <typename U, typename T>
requires llvm_bitcast<U, T>::is_ok
static auto bitcast(T&& expr)
{
return llvm_bitcast<U, T>{std::forward<T>(expr)};
}
template <typename U, typename T, typename = std::enable_if_t<llvm_fpcast<U, T>::is_ok>>
template <typename U, typename T>
requires llvm_fpcast<U, T>::is_ok
static auto fpcast(T&& expr)
{
return llvm_fpcast<U, T>{std::forward<T>(expr)};
}
template <typename U, typename T, typename = std::enable_if_t<llvm_trunc<U, T>::is_ok>>
template <typename U, typename T>
requires llvm_trunc<U, T>::is_ok
static auto trunc(T&& expr)
{
return llvm_trunc<U, T>{std::forward<T>(expr)};
}
template <typename U, typename T, typename = std::enable_if_t<llvm_sext<U, T>::is_ok>>
template <typename U, typename T>
requires llvm_sext<U, T>::is_ok
static auto sext(T&& expr)
{
return llvm_sext<U, T>{std::forward<T>(expr)};
}
template <typename U, typename T, typename = std::enable_if_t<llvm_zext<U, T>::is_ok>>
template <typename U, typename T>
requires llvm_zext<U, T>::is_ok
static auto zext(T&& expr)
{
return llvm_zext<U, T>{std::forward<T>(expr)};
}
template <typename T, typename U, typename V, typename = std::enable_if_t<llvm_select<T, U, V>::is_ok>>
template <typename T, typename U, typename V>
requires llvm_select<T, U, V>::is_ok
static auto select(T&& c, U&& a, V&& b)
{
return llvm_select<T, U, V>{std::forward<T>(c), std::forward<U>(a), std::forward<V>(b)};
}
template <typename T, typename U, typename = std::enable_if_t<llvm_min<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_min<T, U>::is_ok
static auto min(T&& a, U&& b)
{
return llvm_min<T, U>{std::forward<T>(a), std::forward<U>(b)};
}
template <typename T, typename U, typename = std::enable_if_t<llvm_min<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_min<T, U>::is_ok
static auto max(T&& a, U&& b)
{
return llvm_max<T, U>{std::forward<T>(a), std::forward<U>(b)};
}
template <typename T, typename U, typename V, typename = std::enable_if_t<llvm_fshl<T, U, V>::is_ok>>
template <typename T, typename U, typename V>
requires llvm_fshl<T, U, V>::is_ok
static auto fshl(T&& a, U&& b, V&& c)
{
return llvm_fshl<T, U, V>{std::forward<T>(a), std::forward<U>(b), std::forward<V>(c)};
}
template <typename T, typename U, typename V, typename = std::enable_if_t<llvm_fshr<T, U, V>::is_ok>>
template <typename T, typename U, typename V>
requires llvm_fshr<T, U, V>::is_ok
static auto fshr(T&& a, U&& b, V&& c)
{
return llvm_fshr<T, U, V>{std::forward<T>(a), std::forward<U>(b), std::forward<V>(c)};
}
template <typename T, typename U, typename = std::enable_if_t<llvm_rol<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_rol<T, U>::is_ok
static auto rol(T&& a, U&& b)
{
return llvm_rol<T, U>{std::forward<T>(a), std::forward<U>(b)};
}
template <typename T, typename U, typename = std::enable_if_t<llvm_add_sat<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_add_sat<T, U>::is_ok
static auto add_sat(T&& a, U&& b)
{
return llvm_add_sat<T, U>{std::forward<T>(a), std::forward<U>(b)};
}
template <typename T, typename U, typename = std::enable_if_t<llvm_sub_sat<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_sub_sat<T, U>::is_ok
static auto sub_sat(T&& a, U&& b)
{
return llvm_sub_sat<T, U>{std::forward<T>(a), std::forward<U>(b)};
}
template <typename T, typename U, typename = std::enable_if_t<llvm_extract<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_extract<T, U>::is_ok
static auto extract(T&& v, U&& i)
{
return llvm_extract<T, U>{std::forward<T>(v), std::forward<U>(i)};
}
template <typename T, typename = std::enable_if_t<llvm_extract<T, llvm_const_int<u32>>::is_ok>>
template <typename T>
requires llvm_extract<T, llvm_const_int<u32>>::is_ok
static auto extract(T&& v, u32 i)
{
return llvm_extract<T, llvm_const_int<u32>>{std::forward<T>(v), llvm_const_int<u32>{i}};
}
template <typename T, typename U, typename V, typename = std::enable_if_t<llvm_insert<T, U, V>::is_ok>>
template <typename T, typename U, typename V>
requires llvm_insert<T, U, V>::is_ok
static auto insert(T&& v, U&& i, V&& e)
{
return llvm_insert<T, U, V>{std::forward<T>(v), std::forward<U>(i), std::forward<V>(e)};
}
template <typename T, typename V, typename = std::enable_if_t<llvm_insert<T, llvm_const_int<u32>, V>::is_ok>>
template <typename T, typename V>
requires llvm_insert<T, llvm_const_int<u32>, V>::is_ok
static auto insert(T&& v, u32 i, V&& e)
{
return llvm_insert<T, llvm_const_int<u32>, V>{std::forward<T>(v), llvm_const_int<u32>{i}, std::forward<V>(e)};
}
template <typename T, typename = std::enable_if_t<llvm_const_int<T>::is_ok>>
template <typename T>
requires llvm_const_int<T>::is_ok
static auto splat(u64 c)
{
return llvm_const_int<T>{c};
}
template <typename T, typename = std::enable_if_t<llvm_const_float<T>::is_ok>>
template <typename T>
requires llvm_const_float<T>::is_ok
static auto fsplat(f64 c)
{
return llvm_const_float<T>{c};
}
template <typename T, typename U, typename = std::enable_if_t<llvm_splat<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_splat<T, U>::is_ok
static auto vsplat(U&& v)
{
return llvm_splat<T, U>{std::forward<U>(v)};
}
template <typename T, typename... Args, typename = std::enable_if_t<llvm_const_vector<sizeof...(Args), T>::is_ok>>
template <typename T, typename... Args>
requires llvm_const_vector<sizeof...(Args), T>::is_ok
static auto build(Args... args)
{
return llvm_const_vector<sizeof...(Args), T>{static_cast<std::remove_extent_t<T>>(args)...};
}
template <typename T, typename... Args, typename = std::enable_if_t<llvm_zshuffle<sizeof...(Args), T>::is_ok>>
template <typename T, typename... Args>
requires llvm_zshuffle<sizeof...(Args), T>::is_ok
static auto zshuffle(T&& v, Args... indices)
{
return llvm_zshuffle<sizeof...(Args), T>{std::forward<T>(v), {static_cast<int>(indices)...}};
}
template <typename T, typename U, typename... Args, typename = std::enable_if_t<llvm_shuffle2<sizeof...(Args), T, U>::is_ok>>
template <typename T, typename U, typename... Args>
requires llvm_shuffle2<sizeof...(Args), T, U>::is_ok
static auto shuffle2(T&& v1, U&& v2, Args... indices)
{
return llvm_shuffle2<sizeof...(Args), T, U>{std::forward<T>(v1), std::forward<U>(v2), {static_cast<int>(indices)...}};
}
template <typename T, typename = std::enable_if_t<llvm_ctlz<T>::is_ok>>
template <typename T>
requires llvm_ctlz<T>::is_ok
static auto ctlz(T&& a)
{
return llvm_ctlz<T>{std::forward<T>(a)};
}
template <typename T, typename = std::enable_if_t<llvm_ctpop<T>::is_ok>>
template <typename T>
requires llvm_ctpop<T>::is_ok
static auto ctpop(T&& a)
{
return llvm_ctpop<T>{std::forward<T>(a)};
}
// Average: (a + b + 1) >> 1
template <typename T, typename U, typename = std::enable_if_t<llvm_avg<T, U>::is_ok>>
template <typename T, typename U>
requires llvm_avg<T, U>::is_ok
static auto avg(T&& a, U&& b)
{
return llvm_avg<T, U>{std::forward<T>(a), std::forward<U>(b)};
}
template <typename T, typename = std::enable_if_t<llvm_fsqrt<T>::is_ok>>
template <typename T>
requires llvm_fsqrt<T>::is_ok
static auto fsqrt(T&& a)
{
return llvm_fsqrt<T>{std::forward<T>(a)};
}
template <typename T, typename = std::enable_if_t<llvm_fabs<T>::is_ok>>
template <typename T>
requires llvm_fabs<T>::is_ok
static auto fabs(T&& a)
{
return llvm_fabs<T>{std::forward<T>(a)};
}
// Optionally opportunistic hardware FMA, can be used if results are identical for all possible input values
template <typename T, typename U, typename V, typename = std::enable_if_t<llvm_fmuladd<T, U, V>::is_ok>>
template <typename T, typename U, typename V>
requires llvm_fmuladd<T, U, V>::is_ok
static auto fmuladd(T&& a, U&& b, V&& c, bool strict_fma)
{
return llvm_fmuladd<T, U, V>{std::forward<T>(a), std::forward<U>(b), std::forward<V>(c), strict_fma};
}
// Opportunistic hardware FMA, can be used if results are identical for all possible input values
template <typename T, typename U, typename V, typename = std::enable_if_t<llvm_fmuladd<T, U, V>::is_ok>>
template <typename T, typename U, typename V>
requires llvm_fmuladd<T, U, V>::is_ok
auto fmuladd(T&& a, U&& b, V&& c)
{
return llvm_fmuladd<T, U, V>{std::forward<T>(a), std::forward<U>(b), std::forward<V>(c), m_use_fma};
@ -3754,7 +3794,8 @@ public:
return load_const(g, i, get_type<T>());
}
template <typename T, typename I> requires requires () { std::declval<I>().eval(std::declval<llvm::IRBuilder<>*>()); }
template <typename T, typename I>
requires requires(I& i, llvm::IRBuilder<>* ir) { i.eval(ir); }
value_t<T> load_const(llvm::GlobalVariable* g, I i)
{
value_t<T> result;
@ -3873,7 +3914,8 @@ public:
return llvm_calli<u8[16], T, U, V>{"any_select_by_bit4", {std::forward<T>(m), std::forward<U>(a), std::forward<V>(b)}};
}
template <typename T, typename = std::enable_if_t<std::is_same_v<llvm_common_t<T>, f32[4]>>>
template <typename T>
requires std::is_same_v<llvm_common_t<T>, f32[4]>
static auto fre(T&& a)
{
#if defined(ARCH_X64)
@ -3883,7 +3925,8 @@ public:
#endif
}
template <typename T, typename = std::enable_if_t<std::is_same_v<llvm_common_t<T>, f32[4]>>>
template <typename T>
requires std::is_same_v<llvm_common_t<T>, f32[4]>
static auto frsqe(T&& a)
{
#if defined(ARCH_X64)
@ -3893,7 +3936,8 @@ public:
#endif
}
template <typename T, typename U, typename = std::enable_if_t<std::is_same_v<llvm_common_t<T, U>, f32[4]>>>
template <typename T, typename U>
requires std::is_same_v<llvm_common_t<T, U>, f32[4]>
static auto fmax(T&& a, U&& b)
{
#if defined(ARCH_X64)
@ -3903,7 +3947,8 @@ public:
#endif
}
template <typename T, typename U, typename = std::enable_if_t<std::is_same_v<llvm_common_t<T, U>, f32[4]>>>
template <typename T, typename U>
requires std::is_same_v<llvm_common_t<T, U>, f32[4]>
static auto fmin(T&& a, U&& b)
{
#if defined(ARCH_X64)
@ -3913,13 +3958,15 @@ public:
#endif
}
template <typename T, typename U, typename = std::enable_if_t<std::is_same_v<llvm_common_t<T, U>, u8[16]>>>
template <typename T, typename U>
requires std::is_same_v<llvm_common_t<T, U>, u8[16]>
static auto vdbpsadbw(T&& a, U&& b, u8 c)
{
return llvm_calli<u16[8], T, U, llvm_const_int<u32>>{"llvm.x86.avx512.dbpsadbw.128", {std::forward<T>(a), std::forward<U>(b), llvm_const_int<u32>{c}}};
}
template <typename T, typename U, typename = std::enable_if_t<std::is_same_v<llvm_common_t<T, U>, f32[4]>>>
template <typename T, typename U>
requires std::is_same_v<llvm_common_t<T, U>, f32[4]>
static auto vrangeps(T&& a, U&& b, u8 c, u8 d)
{
return llvm_calli<f32[4], T, U, llvm_const_int<u32>, T, llvm_const_int<u8>>{"llvm.x86.avx512.mask.range.ps.128", {std::forward<T>(a), std::forward<U>(b), llvm_const_int<u32>{c}, std::forward<T>(a), llvm_const_int<u8>{d}}};
@ -3928,7 +3975,7 @@ public:
// Format llvm::SizeType
template <>
struct fmt_unveil<llvm::TypeSize, void>
struct fmt_unveil<llvm::TypeSize>
{
using type = usz;

View file

@ -82,11 +82,11 @@ constexpr FORCE_INLINE CellNotAnError not_an_error(const T& value)
return static_cast<CellNotAnError>(static_cast<s32>(value));
}
template <typename T, typename>
template <typename T>
struct ppu_gpr_cast_impl;
template <>
struct ppu_gpr_cast_impl<error_code, void>
struct ppu_gpr_cast_impl<error_code>
{
static inline u64 to(const error_code& code)
{

View file

@ -672,11 +672,11 @@ union CellSailEvent
be_t<u64> value;
};
template<typename T, typename>
template <typename T>
struct ppu_gpr_cast_impl;
template<>
struct ppu_gpr_cast_impl<CellSailEvent, void>
template <>
struct ppu_gpr_cast_impl<CellSailEvent>
{
static inline u64 to(const CellSailEvent& event)
{

View file

@ -3,6 +3,7 @@
#include "util/types.hpp"
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/ErrorCodes.h"
#include <mutex>
#include <vector>
#include <mutex>

View file

@ -382,14 +382,15 @@ public:
static_assert(ppu_join_status::max <= ppu_join_status{ppu_thread::id_base});
template<typename T, typename = void>
template <typename T>
struct ppu_gpr_cast_impl
{
static_assert(!sizeof(T), "Invalid type for ppu_gpr_cast<>");
};
template<typename T>
struct ppu_gpr_cast_impl<T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>
template <typename T>
requires std::is_integral_v<T> || std::is_enum_v<T>
struct ppu_gpr_cast_impl<T>
{
static_assert(sizeof(T) <= 8, "Too big integral type for ppu_gpr_cast<>()");
static_assert(std::is_same_v<std::decay_t<T>, bool> == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead");
@ -405,8 +406,8 @@ struct ppu_gpr_cast_impl<T, std::enable_if_t<std::is_integral_v<T> || std::is_en
}
};
template<>
struct ppu_gpr_cast_impl<b8, void>
template <>
struct ppu_gpr_cast_impl<b8>
{
static inline u64 to(const b8& value)
{
@ -419,8 +420,8 @@ struct ppu_gpr_cast_impl<b8, void>
}
};
template<typename T, typename AT>
struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>, void>
template <typename T, typename AT>
struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>>
{
static inline u64 to(const vm::_ptr_base<T, AT>& value)
{
@ -433,8 +434,8 @@ struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>, void>
}
};
template<typename T, typename AT>
struct ppu_gpr_cast_impl<vm::_ref_base<T, AT>, void>
template <typename T, typename AT>
struct ppu_gpr_cast_impl<vm::_ref_base<T, AT>>
{
static inline u64 to(const vm::_ref_base<T, AT>& value)
{
@ -448,7 +449,7 @@ struct ppu_gpr_cast_impl<vm::_ref_base<T, AT>, void>
};
template <>
struct ppu_gpr_cast_impl<vm::null_t, void>
struct ppu_gpr_cast_impl<vm::null_t>
{
static inline u64 to(const vm::null_t& /*value*/)
{

View file

@ -26,7 +26,7 @@ template <typename T>
concept IdmBaseCompatible = (std::is_final_v<T> ? IdmCompatible<T> : !!(requires () { u32{T::id_step}, u32{T::id_count}; }));
template <typename T>
concept IdmSavable = IdmBaseCompatible<T> && T::savestate_init_pos != 0 && (requires () { std::declval<T>().save(std::declval<stx::exact_t<utils::serial&>>()); });
concept IdmSavable = IdmBaseCompatible<T> && T::savestate_init_pos != 0 && (requires(T& t, utils::serial& ar) { t.save(stx::exact_t<utils::serial&>(ar)); });
// If id_base is declared in base type, than storage type must declare id_type
template <typename Base, typename Type>
@ -105,7 +105,7 @@ namespace id_manager
}
// ID traits
template <typename T, typename = void>
template <typename T>
struct id_traits_load_func
{
static constexpr pointer_keeper(*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper
@ -126,7 +126,8 @@ namespace id_manager
};
template <typename T>
struct id_traits_load_func<T, std::void_t<decltype(&T::load)>>
requires requires() { &T::load; }
struct id_traits_load_func<T>
{
static constexpr pointer_keeper(*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper
{
@ -134,14 +135,15 @@ namespace id_manager
};
};
template <typename T, typename = void>
template <typename T>
struct id_traits_savable_func
{
static constexpr bool(*savable)(void*) = [](void*) -> bool { return true; };
};
template <typename T>
struct id_traits_savable_func<T, std::void_t<decltype(&T::savable)>>
requires requires { &T::savable; }
struct id_traits_savable_func<T>
{
static constexpr bool(*savable)(void* ptr) = [](void* ptr) -> bool { return static_cast<const T*>(ptr)->savable(); };
};

View file

@ -342,21 +342,24 @@ namespace vm
template<typename T, typename AT = u32, typename AT2 = u32> using bcpptr = bpptr<const T, AT, AT2>;
// Perform static_cast (for example, vm::ptr<void> to vm::ptr<char>)
template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_be_t<CT>*>(std::declval<T*>()))>
template <typename CT, typename T, typename AT>
requires requires(T* t) { static_cast<to_be_t<CT>*>(t); }
inline _ptr_base<to_be_t<CT>, u32> static_ptr_cast(const _ptr_base<T, AT>& other)
{
return vm::cast(other.addr());
}
// Perform const_cast (for example, vm::cptr<char> to vm::ptr<char>)
template<typename CT, typename T, typename AT, typename = decltype(const_cast<to_be_t<CT>*>(std::declval<T*>()))>
template <typename CT, typename T, typename AT>
requires requires(T* t) { const_cast<to_be_t<CT>*>(t); }
inline _ptr_base<to_be_t<CT>, u32> const_ptr_cast(const _ptr_base<T, AT>& other)
{
return vm::cast(other.addr());
}
// Perform reinterpret cast
template <typename CT, typename T, typename AT, typename = decltype(reinterpret_cast<to_be_t<CT>*>(std::declval<T*>()))>
template <typename CT, typename T, typename AT>
requires requires(T* t) { reinterpret_cast<to_be_t<CT>*>(t); }
inline _ptr_base<to_be_t<CT>, u32> unsafe_ptr_cast(const _ptr_base<T, AT>& other)
{
return vm::cast(other.addr());
@ -426,8 +429,8 @@ struct to_se<vm::_ptr_base<T, AT>, Se>
};
// Format pointer
template<typename T, typename AT>
struct fmt_unveil<vm::_ptr_base<T, AT>, void>
template <typename T, typename AT>
struct fmt_unveil<vm::_ptr_base<T, AT>>
{
using type = vm::_ptr_base<T, u32>; // Use only T, ignoring AT

View file

@ -193,8 +193,8 @@ struct to_se<vm::_ref_base<T, AT>, Se>
};
// Forbid formatting
template<typename T, typename AT>
struct fmt_unveil<vm::_ref_base<T, AT>, void>
template <typename T, typename AT>
struct fmt_unveil<vm::_ref_base<T, AT>>
{
static_assert(!sizeof(T), "vm::_ref_base<>: ambiguous format argument");
};

View file

@ -94,11 +94,11 @@ namespace rsx
return value;
}
template<typename = std::enable_if<!std::is_same_v<T, bool>>>
operator bool() const
{
return error.empty();
}
operator bool() const
requires(!std::is_same_v<T, bool>)
{
return error.empty();
}
operator std::pair<T&, E&>() const
{

View file

@ -376,21 +376,24 @@ namespace utils
}
// Align to power of 2
template <typename T, typename U, typename = std::enable_if_t<std::is_unsigned_v<T>>>
template <typename T, typename U>
requires std::is_unsigned_v<T>
constexpr std::make_unsigned_t<std::common_type_t<T, U>> align(T value, U align)
{
return static_cast<std::make_unsigned_t<std::common_type_t<T, U>>>((value + (align - 1)) & (T{0} - align));
}
// General purpose aligned division, the result is rounded up not truncated
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
template <typename T>
requires std::is_unsigned_v<T>
constexpr T aligned_div(T value, std::type_identity_t<T> align)
{
return static_cast<T>(value / align + T{!!(value % align)});
}
// General purpose aligned division, the result is rounded to nearest
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
template <typename T>
requires std::is_integral_v<T>
constexpr T rounded_div(T value, std::type_identity_t<T> align)
{
if constexpr (std::is_unsigned_v<T>)

View file

@ -173,7 +173,8 @@ namespace atomic_wait
constexpr list& operator=(const list&) noexcept = default;
template <typename... U, typename = std::void_t<decltype(std::declval<U>().wait(any_value))...>>
template <typename... U>
requires(requires(U& u) { u.wait(any_value); } && ...)
constexpr list(U&... vars)
: m_info{{&vars, 0}...}
{
@ -190,7 +191,8 @@ namespace atomic_wait
return *this;
}
template <uint Index, typename T2, typename U, typename = std::void_t<decltype(std::declval<T2>().wait(any_value))>>
template <uint Index, typename T2, typename U>
requires(requires(T2& t2) { t2.wait(any_value); })
constexpr void set(T2& var, U value)
{
static_assert(Index < Max);
@ -229,7 +231,8 @@ namespace atomic_wait
}
};
template <typename... T, typename = std::void_t<decltype(std::declval<T>().wait(any_value))...>>
template <typename... T>
requires(requires(T& t) { t.wait(any_value); } && ...)
list(T&... vars) -> list<sizeof...(T), T...>;
}

View file

@ -267,8 +267,9 @@ private:
}
}
public:
template <typename T2, typename = decltype(+std::declval<const T2&>())>
public:
template <typename T2>
requires requires(const T2& t2) { +t2; }
constexpr bool operator==(const T2& rhs) const noexcept
{
using R = std::common_type_t<T2>;

View file

@ -143,7 +143,8 @@ namespace stx
*std::launder(static_cast<T*>(ptr)) = state;
}
template <typename T> requires requires (T& a) { a.save(std::declval<stx::exact_t<utils::serial&>>()); }
template <typename T>
requires requires(T& a, utils::serial& ar) { a.save(ar); }
static void call_save(void* ptr, utils::serial& ar) noexcept
{
std::launder(static_cast<T*>(ptr))->save(stx::exact_t<utils::serial&>(ar));
@ -169,7 +170,7 @@ namespace stx
r.thread_op = &call_thread_op<T>;
}
if constexpr (!!(requires (T& a) { a.save(std::declval<stx::exact_t<utils::serial&>>()); }))
if constexpr (!!(requires(T& a, utils::serial& ar) { a.save(ar); }))
{
r.save = &call_save<T>;
}

View file

@ -14,7 +14,8 @@ namespace rpcs3
return static_cast<usz>(value);
}
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
template <typename T>
requires std::is_integral_v<T>
static inline usz hash64(usz hash_value, T data)
{
hash_value ^= data;

View file

@ -18,9 +18,8 @@ namespace utils
};
template <typename T>
concept Bitcopy = (std::is_arithmetic_v<T>) || (std::is_enum_v<T>) || Integral<T> || requires ()
{
std::enable_if_t<std::conjunction_v<typename T::enable_bitcopy>>();
concept Bitcopy = (std::is_arithmetic_v<T>) || (std::is_enum_v<T>) || Integral<T> || requires() {
typename T::enable_bitcopy;
};
template <typename T>
@ -30,7 +29,7 @@ namespace utils
};
template <typename T>
concept ListAlike = requires (std::remove_cvref_t<T>& obj) { obj.insert(obj.end(), std::declval<typename T::value_type>()); };
concept ListAlike = requires(std::remove_cvref_t<T>& obj, T::value_type item) { obj.insert(obj.end(), item); };
struct serial;
@ -427,7 +426,8 @@ public:
return true;
}
template <typename T> requires requires (T& obj) { (obj.*(&T::operator()))(std::declval<stx::exact_t<utils::serial&>>()); }
template <typename T>
requires requires(T& obj, utils::serial& ar) { (obj.*(&T::operator()))(ar); }
bool serialize(T& obj)
{
obj(*this);

View file

@ -6,17 +6,18 @@
union v128;
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
template <typename T, bool Se, typename = void>
template <typename T, bool Se>
struct to_se
{
template <typename T2, typename = void>
template <typename T2>
struct to_se_
{
using type = T2;
};
template <typename T2>
struct to_se_<T2, std::enable_if_t<std::is_arithmetic_v<T2> || std::is_enum_v<T2>>>
requires std::is_arithmetic_v<T2> || std::is_enum_v<T2>
struct to_se_<T2>
{
using type = std::conditional_t<(sizeof(T2) > 1), se_t<T2, Se>, T2>;
};
@ -44,14 +45,16 @@ struct to_se<s128, Se>
};
template <typename T, bool Se>
struct to_se<const T, Se, std::enable_if_t<!std::is_array_v<T>>>
requires(!std::is_array_v<T>)
struct to_se<const T, Se>
{
// Move const qualifier
using type = const typename to_se<T, Se>::type;
};
template <typename T, bool Se>
struct to_se<volatile T, Se, std::enable_if_t<!std::is_array_v<T> && !std::is_const_v<T>>>
requires(!std::is_array_v<T> && !std::is_const_v<T>)
struct to_se<volatile T, Se>
{
// Move volatile qualifier
using type = volatile typename to_se<T, Se>::type;

View file

@ -272,14 +272,16 @@ struct alignas(16) u128
u128() noexcept = default;
template <typename T, std::enable_if_t<std::is_unsigned_v<T>, u64> = 0>
template <typename T>
requires std::is_unsigned_v<T>
constexpr u128(T arg) noexcept
: lo(arg)
, hi(0)
{
}
template <typename T, std::enable_if_t<std::is_signed_v<T>, s64> = 0>
template <typename T>
requires std::is_signed_v<T>
constexpr u128(T arg) noexcept
: lo(s64{arg})
, hi(s64{arg} >> 63)