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 #endif
template <typename T, uint I, uint N> 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; 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> 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; 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> 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; using type = typename fmt_unveil<std::common_type_t<T>>::type;

View file

@ -22,7 +22,7 @@ namespace fmt
#endif #endif
} }
template <typename T, typename = void> template <typename T>
struct fmt_unveil struct fmt_unveil
{ {
static_assert(sizeof(T) > 0, "fmt_unveil<> error: incomplete type"); static_assert(sizeof(T) > 0, "fmt_unveil<> error: incomplete type");
@ -54,7 +54,8 @@ struct fmt_unveil
}; };
template <typename T> 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; 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> 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; 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> 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; using type = T;
@ -88,7 +91,7 @@ struct fmt_unveil<T, std::enable_if_t<std::is_enum_v<T>>>
}; };
template <typename T> template <typename T>
struct fmt_unveil<T*, void> struct fmt_unveil<T*>
{ {
using type = std::add_const_t<T>*; using type = std::add_const_t<T>*;
@ -105,7 +108,7 @@ namespace fmt
} }
template <fmt::CharT T, usz N> template <fmt::CharT T, usz N>
struct fmt_unveil<T[N], void> struct fmt_unveil<T[N]>
{ {
using type = std::add_const_t<T>*; using type = std::add_const_t<T>*;
@ -116,7 +119,7 @@ struct fmt_unveil<T[N], void>
}; };
template <typename T, bool Se, usz Align> 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; using type = typename fmt_unveil<T>::type;
@ -200,13 +203,13 @@ struct fmt_class_string
}; };
template <> template <>
struct fmt_class_string<const void*, void> struct fmt_class_string<const void*>
{ {
static void format(std::string& out, u64 arg); static void format(std::string& out, u64 arg);
}; };
template <typename T> 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* // Classify all pointers as const void*
}; };
@ -218,18 +221,18 @@ struct fmt_class_string<const char*, void>
}; };
template <> 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* // Classify char* as const char*
}; };
template <> 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 <> 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 <> 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> template <typename T>
struct fmt_unveil<bs_t<T>, void> struct fmt_unveil<bs_t<T>>
{ {
// Format as is // Format as is
using type = bs_t<T>; using type = bs_t<T>;

View file

@ -110,7 +110,8 @@ protected:
virtual u32 DisAsmBranchTarget(s32 /*imm*/); virtual u32 DisAsmBranchTarget(s32 /*imm*/);
// TODO: Add builtin fmt helpper for best performance // 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) static std::string SignedHex(T value)
{ {
const auto v = static_cast<std::make_signed_t<T>>(value); const auto v = static_cast<std::make_signed_t<T>>(value);

View file

@ -2,6 +2,12 @@
#ifdef LLVM_AVAILABLE #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 #ifdef _MSC_VER
#pragma warning(push, 0) #pragma warning(push, 0)
#else #else
@ -24,7 +30,9 @@
#include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/IntrinsicsX86.h"
#ifdef ARCH_ARM64
#include "llvm/IR/IntrinsicsAArch64.h" #include "llvm/IR/IntrinsicsAArch64.h"
#endif
#include "llvm/IR/InlineAsm.h" #include "llvm/IR/InlineAsm.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@ -33,12 +41,6 @@
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#include "util/types.hpp"
#include "util/sysinfo.hpp"
#include "Utilities/StrFmt.h"
#include "Utilities/JIT.h"
#include "util/v128.hpp"
#include <functional> #include <functional>
#include <unordered_map> #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>>); concept LLVMValue = (std::is_pointer_v<T>) && (std::is_base_of_v<llvm::Value, std::remove_pointer_t<T>>);
template <typename T> template <typename T>
concept DSLValue = requires (T& v) concept DSLValue = requires(T& v, llvm::IRBuilder<>* ir) {
{ { v.eval(ir) } -> LLVMValue;
{ v.eval(std::declval<llvm::IRBuilder<>*>()) } -> LLVMValue;
}; };
template <usz N> 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> template <typename T>
using llvm_expr_t = std::decay_t<T>; using llvm_expr_t = std::decay_t<T>;
template <typename T, typename = void> template <typename T>
struct is_llvm_expr struct is_llvm_expr
{ {
}; };
template <typename T> template <DSLValue T>
struct is_llvm_expr<T, std::void_t<decltype(std::declval<T>().eval(std::declval<llvm::IRBuilder<>*>()))>> struct is_llvm_expr<T>
{ {
using type = typename std::decay_t<T>::type; 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 struct is_llvm_expr_of
{ {
static constexpr bool ok = false; static constexpr bool ok = false;
}; };
template <typename T, typename Of> 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>; 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> 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> template <typename... Args>
using llvm_match_tuple = decltype(std::tuple_cat(std::declval<llvm_expr_t<Args>&>().match(std::declval<llvm::Value*&>(), nullptr)...)); 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> 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>> template <typename Cmp, typename T = llvm_common_t<Cmp>>
struct llvm_uno struct llvm_uno
@ -1659,7 +1663,8 @@ struct llvm_uno
}; };
template <typename T> 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> template <typename T1, typename T2>
inline llvm_cmp<T1, T2, llvm::ICmpInst::ICMP_EQ> operator ==(T1&& a1, T2&& a2) inline llvm_cmp<T1, T2, llvm::ICmpInst::ICMP_EQ> operator ==(T1&& a1, T2&& a2)
@ -3194,14 +3199,16 @@ public:
return {}; 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) static auto match_expr(llvm::Value* v, llvm::Module* _m, T&& expr)
{ {
auto r = expr.match(v, _m); auto r = expr.match(v, _m);
return std::tuple_cat(std::make_tuple(v != nullptr), r); 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 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); auto v = arg.eval(m_ir);
@ -3236,202 +3243,235 @@ public:
return expr_t<T, F>{std::forward<T>(expr), std::move(matcher)}; 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) static auto fcmp_ord(T&& cmp_expr)
{ {
return llvm_ord{std::forward<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) static auto fcmp_uno(T&& cmp_expr)
{ {
return llvm_uno{std::forward<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) static auto noncast(T&& expr)
{ {
return llvm_noncast<U, T>{std::forward<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) static auto bitcast(T&& expr)
{ {
return llvm_bitcast<U, T>{std::forward<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) static auto fpcast(T&& expr)
{ {
return llvm_fpcast<U, T>{std::forward<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) static auto trunc(T&& expr)
{ {
return llvm_trunc<U, T>{std::forward<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) static auto sext(T&& expr)
{ {
return llvm_sext<U, T>{std::forward<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) static auto zext(T&& expr)
{ {
return llvm_zext<U, T>{std::forward<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) 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)}; 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) static auto min(T&& a, U&& b)
{ {
return llvm_min<T, U>{std::forward<T>(a), std::forward<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) static auto max(T&& a, U&& b)
{ {
return llvm_max<T, U>{std::forward<T>(a), std::forward<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) 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)}; 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) 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)}; 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) static auto rol(T&& a, U&& b)
{ {
return llvm_rol<T, U>{std::forward<T>(a), std::forward<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) static auto add_sat(T&& a, U&& b)
{ {
return llvm_add_sat<T, U>{std::forward<T>(a), std::forward<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) static auto sub_sat(T&& a, U&& b)
{ {
return llvm_sub_sat<T, U>{std::forward<T>(a), std::forward<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) static auto extract(T&& v, U&& i)
{ {
return llvm_extract<T, U>{std::forward<T>(v), std::forward<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) static auto extract(T&& v, u32 i)
{ {
return llvm_extract<T, llvm_const_int<u32>>{std::forward<T>(v), llvm_const_int<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) 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)}; 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) 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)}; 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) static auto splat(u64 c)
{ {
return llvm_const_int<T>{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) static auto fsplat(f64 c)
{ {
return llvm_const_float<T>{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) static auto vsplat(U&& v)
{ {
return llvm_splat<T, U>{std::forward<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) static auto build(Args... args)
{ {
return llvm_const_vector<sizeof...(Args), T>{static_cast<std::remove_extent_t<T>>(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) static auto zshuffle(T&& v, Args... indices)
{ {
return llvm_zshuffle<sizeof...(Args), T>{std::forward<T>(v), {static_cast<int>(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) 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)...}}; 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) static auto ctlz(T&& a)
{ {
return llvm_ctlz<T>{std::forward<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) static auto ctpop(T&& a)
{ {
return llvm_ctpop<T>{std::forward<T>(a)}; return llvm_ctpop<T>{std::forward<T>(a)};
} }
// Average: (a + b + 1) >> 1 // 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) static auto avg(T&& a, U&& b)
{ {
return llvm_avg<T, U>{std::forward<T>(a), std::forward<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) static auto fsqrt(T&& a)
{ {
return llvm_fsqrt<T>{std::forward<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) static auto fabs(T&& a)
{ {
return llvm_fabs<T>{std::forward<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 // 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) 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}; 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 // 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) 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}; 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>()); 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> load_const(llvm::GlobalVariable* g, I i)
{ {
value_t<T> result; 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)}}; 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) static auto fre(T&& a)
{ {
#if defined(ARCH_X64) #if defined(ARCH_X64)
@ -3883,7 +3925,8 @@ public:
#endif #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) static auto frsqe(T&& a)
{ {
#if defined(ARCH_X64) #if defined(ARCH_X64)
@ -3893,7 +3936,8 @@ public:
#endif #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) static auto fmax(T&& a, U&& b)
{ {
#if defined(ARCH_X64) #if defined(ARCH_X64)
@ -3903,7 +3947,8 @@ public:
#endif #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) static auto fmin(T&& a, U&& b)
{ {
#if defined(ARCH_X64) #if defined(ARCH_X64)
@ -3913,13 +3958,15 @@ public:
#endif #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) 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}}}; 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) 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}}}; 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 // Format llvm::SizeType
template <> template <>
struct fmt_unveil<llvm::TypeSize, void> struct fmt_unveil<llvm::TypeSize>
{ {
using type = usz; 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)); return static_cast<CellNotAnError>(static_cast<s32>(value));
} }
template <typename T, typename> template <typename T>
struct ppu_gpr_cast_impl; struct ppu_gpr_cast_impl;
template <> template <>
struct ppu_gpr_cast_impl<error_code, void> struct ppu_gpr_cast_impl<error_code>
{ {
static inline u64 to(const error_code& code) static inline u64 to(const error_code& code)
{ {

View file

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

View file

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

View file

@ -382,14 +382,15 @@ public:
static_assert(ppu_join_status::max <= ppu_join_status{ppu_thread::id_base}); 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 struct ppu_gpr_cast_impl
{ {
static_assert(!sizeof(T), "Invalid type for ppu_gpr_cast<>"); static_assert(!sizeof(T), "Invalid type for ppu_gpr_cast<>");
}; };
template <typename T> template <typename T>
struct ppu_gpr_cast_impl<T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<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(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"); static_assert(std::is_same_v<std::decay_t<T>, bool> == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead");
@ -406,7 +407,7 @@ struct ppu_gpr_cast_impl<T, std::enable_if_t<std::is_integral_v<T> || std::is_en
}; };
template <> template <>
struct ppu_gpr_cast_impl<b8, void> struct ppu_gpr_cast_impl<b8>
{ {
static inline u64 to(const b8& value) static inline u64 to(const b8& value)
{ {
@ -420,7 +421,7 @@ struct ppu_gpr_cast_impl<b8, void>
}; };
template <typename T, typename AT> template <typename T, typename AT>
struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>, void> struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>>
{ {
static inline u64 to(const vm::_ptr_base<T, AT>& value) static inline u64 to(const vm::_ptr_base<T, AT>& value)
{ {
@ -434,7 +435,7 @@ struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>, void>
}; };
template <typename T, typename AT> template <typename T, typename AT>
struct ppu_gpr_cast_impl<vm::_ref_base<T, AT>, void> struct ppu_gpr_cast_impl<vm::_ref_base<T, AT>>
{ {
static inline u64 to(const vm::_ref_base<T, AT>& value) 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 <> 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*/) 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}; })); concept IdmBaseCompatible = (std::is_final_v<T> ? IdmCompatible<T> : !!(requires () { u32{T::id_step}, u32{T::id_count}; }));
template <typename T> 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 // If id_base is declared in base type, than storage type must declare id_type
template <typename Base, typename Type> template <typename Base, typename Type>
@ -105,7 +105,7 @@ namespace id_manager
} }
// ID traits // ID traits
template <typename T, typename = void> template <typename T>
struct id_traits_load_func struct id_traits_load_func
{ {
static constexpr pointer_keeper(*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper static constexpr pointer_keeper(*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper
@ -126,7 +126,8 @@ namespace id_manager
}; };
template <typename T> 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 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 struct id_traits_savable_func
{ {
static constexpr bool(*savable)(void*) = [](void*) -> bool { return true; }; static constexpr bool(*savable)(void*) = [](void*) -> bool { return true; };
}; };
template <typename T> 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(); }; 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>; 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>) // 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) inline _ptr_base<to_be_t<CT>, u32> static_ptr_cast(const _ptr_base<T, AT>& other)
{ {
return vm::cast(other.addr()); return vm::cast(other.addr());
} }
// Perform const_cast (for example, vm::cptr<char> to vm::ptr<char>) // 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) inline _ptr_base<to_be_t<CT>, u32> const_ptr_cast(const _ptr_base<T, AT>& other)
{ {
return vm::cast(other.addr()); return vm::cast(other.addr());
} }
// Perform reinterpret cast // 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) inline _ptr_base<to_be_t<CT>, u32> unsafe_ptr_cast(const _ptr_base<T, AT>& other)
{ {
return vm::cast(other.addr()); return vm::cast(other.addr());
@ -427,7 +430,7 @@ struct to_se<vm::_ptr_base<T, AT>, Se>
// Format pointer // Format pointer
template <typename T, typename AT> template <typename T, typename AT>
struct fmt_unveil<vm::_ptr_base<T, AT>, void> struct fmt_unveil<vm::_ptr_base<T, AT>>
{ {
using type = vm::_ptr_base<T, u32>; // Use only T, ignoring AT using type = vm::_ptr_base<T, u32>; // Use only T, ignoring AT

View file

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

View file

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

View file

@ -376,21 +376,24 @@ namespace utils
} }
// Align to power of 2 // 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) 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)); 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 // 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) constexpr T aligned_div(T value, std::type_identity_t<T> align)
{ {
return static_cast<T>(value / align + T{!!(value % align)}); return static_cast<T>(value / align + T{!!(value % align)});
} }
// General purpose aligned division, the result is rounded to nearest // 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) constexpr T rounded_div(T value, std::type_identity_t<T> align)
{ {
if constexpr (std::is_unsigned_v<T>) if constexpr (std::is_unsigned_v<T>)

View file

@ -173,7 +173,8 @@ namespace atomic_wait
constexpr list& operator=(const list&) noexcept = default; 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) constexpr list(U&... vars)
: m_info{{&vars, 0}...} : m_info{{&vars, 0}...}
{ {
@ -190,7 +191,8 @@ namespace atomic_wait
return *this; 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) constexpr void set(T2& var, U value)
{ {
static_assert(Index < Max); 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...>; list(T&... vars) -> list<sizeof...(T), T...>;
} }

View file

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

View file

@ -143,7 +143,8 @@ namespace stx
*std::launder(static_cast<T*>(ptr)) = state; *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 static void call_save(void* ptr, utils::serial& ar) noexcept
{ {
std::launder(static_cast<T*>(ptr))->save(stx::exact_t<utils::serial&>(ar)); 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>; 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>; r.save = &call_save<T>;
} }

View file

@ -14,7 +14,8 @@ namespace rpcs3
return static_cast<usz>(value); 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) static inline usz hash64(usz hash_value, T data)
{ {
hash_value ^= data; hash_value ^= data;

View file

@ -18,9 +18,8 @@ namespace utils
}; };
template <typename T> template <typename T>
concept Bitcopy = (std::is_arithmetic_v<T>) || (std::is_enum_v<T>) || Integral<T> || requires () concept Bitcopy = (std::is_arithmetic_v<T>) || (std::is_enum_v<T>) || Integral<T> || requires() {
{ typename T::enable_bitcopy;
std::enable_if_t<std::conjunction_v<typename T::enable_bitcopy>>();
}; };
template <typename T> template <typename T>
@ -30,7 +29,7 @@ namespace utils
}; };
template <typename T> 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; struct serial;
@ -427,7 +426,8 @@ public:
return true; 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) bool serialize(T& obj)
{ {
obj(*this); obj(*this);

View file

@ -6,17 +6,18 @@
union v128; union v128;
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type // 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 struct to_se
{ {
template <typename T2, typename = void> template <typename T2>
struct to_se_ struct to_se_
{ {
using type = T2; using type = T2;
}; };
template <typename 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>; 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> 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 // Move const qualifier
using type = const typename to_se<T, Se>::type; using type = const typename to_se<T, Se>::type;
}; };
template <typename T, bool Se> 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 // Move volatile qualifier
using type = volatile typename to_se<T, Se>::type; using type = volatile typename to_se<T, Se>::type;

View file

@ -272,14 +272,16 @@ struct alignas(16) u128
u128() noexcept = default; 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 constexpr u128(T arg) noexcept
: lo(arg) : lo(arg)
, hi(0) , 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 constexpr u128(T arg) noexcept
: lo(s64{arg}) : lo(s64{arg})
, hi(s64{arg} >> 63) , hi(s64{arg} >> 63)