File indexing completed on 2025-08-28 09:11:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef XSIMD_TRAITS_HPP
0013 #define XSIMD_TRAITS_HPP
0014
0015 #include <type_traits>
0016
0017 #include "xsimd_batch.hpp"
0018
0019
0020
0021
0022
0023
0024
0025
0026 namespace xsimd
0027 {
0028
0029
0030
0031
0032
0033 template <class T, class A = default_arch>
0034 struct has_simd_register : types::has_simd_register<T, A>
0035 {
0036 };
0037
0038 template <class T, class A>
0039 struct has_simd_register<std::complex<T>, A> : has_simd_register<T, A>
0040 {
0041 };
0042
0043 namespace detail
0044 {
0045 template <class T, bool>
0046 struct simd_traits_impl;
0047
0048 template <class T>
0049 struct simd_traits_impl<T, false>
0050 {
0051 using type = T;
0052 using bool_type = bool;
0053 static constexpr size_t size = 1;
0054 };
0055
0056 template <class T>
0057 constexpr size_t simd_traits_impl<T, false>::size;
0058
0059 template <class T>
0060 struct simd_traits_impl<T, true>
0061 {
0062 using type = batch<T>;
0063 using bool_type = typename type::batch_bool_type;
0064 static constexpr size_t size = type::size;
0065 };
0066
0067 template <class T>
0068 constexpr size_t simd_traits_impl<T, true>::size;
0069
0070 template <class T, class A>
0071 struct static_check_supported_config_emitter
0072 {
0073
0074 static_assert(A::supported(),
0075 "usage of batch type with unsupported architecture");
0076 static_assert(!A::supported() || xsimd::has_simd_register<T, A>::value,
0077 "usage of batch type with unsupported type");
0078 };
0079
0080 template <class T, class A>
0081 struct static_check_supported_config_emitter<std::complex<T>, A> : static_check_supported_config_emitter<T, A>
0082 {
0083 };
0084
0085 #ifdef XSIMD_ENABLE_XTL_COMPLEX
0086 template <class T, class A, bool i3ec>
0087 struct static_check_supported_config_emitter<xtl::xcomplex<T, T, i3ec>, A> : static_check_supported_config_emitter<T, A>
0088 {
0089 };
0090 #endif
0091
0092
0093 template <class T, class A>
0094 XSIMD_INLINE void static_check_supported_config()
0095 {
0096 (void)static_check_supported_config_emitter<T, A>();
0097 }
0098 }
0099
0100 template <class T>
0101 struct simd_traits : detail::simd_traits_impl<T, xsimd::has_simd_register<T>::value>
0102 {
0103 };
0104
0105 template <class T>
0106 struct simd_traits<std::complex<T>>
0107 : detail::simd_traits_impl<std::complex<T>, xsimd::has_simd_register<T>::value>
0108 {
0109 };
0110
0111 #ifdef XSIMD_ENABLE_XTL_COMPLEX
0112 template <class T, bool i3ec>
0113 struct simd_traits<xtl::xcomplex<T, T, i3ec>>
0114 : detail::simd_traits_impl<std::complex<T>, xsimd::has_simd_register<T>::value>
0115 {
0116 };
0117 #endif
0118
0119 template <class T>
0120 struct revert_simd_traits
0121 {
0122 using type = T;
0123 static constexpr size_t size = simd_traits<type>::size;
0124 };
0125
0126 template <class T>
0127 constexpr size_t revert_simd_traits<T>::size;
0128
0129 template <class T>
0130 struct revert_simd_traits<batch<T>>
0131 {
0132 using type = T;
0133 static constexpr size_t size = batch<T>::size;
0134 };
0135
0136 template <class T>
0137 constexpr size_t revert_simd_traits<batch<T>>::size;
0138
0139 template <class T>
0140 using simd_type = typename simd_traits<T>::type;
0141
0142 template <class T>
0143 using simd_bool_type = typename simd_traits<T>::bool_type;
0144
0145 template <class T>
0146 using revert_simd_type = typename revert_simd_traits<T>::type;
0147
0148
0149
0150
0151
0152 namespace detail
0153 {
0154 template <class T1, class T2>
0155 struct simd_condition
0156 {
0157 static constexpr bool value = (std::is_same<T1, T2>::value && !std::is_same<T1, bool>::value) || (std::is_same<T1, bool>::value && !std::is_same<T2, bool>::value) || std::is_same<T1, float>::value || std::is_same<T1, double>::value || std::is_same<T1, int8_t>::value || std::is_same<T1, uint8_t>::value || std::is_same<T1, int16_t>::value || std::is_same<T1, uint16_t>::value || std::is_same<T1, int32_t>::value || std::is_same<T1, uint32_t>::value || std::is_same<T1, int64_t>::value || std::is_same<T1, uint64_t>::value || std::is_same<T1, char>::value || detail::is_complex<T1>::value;
0158 };
0159
0160 template <class T1, class T2, class A>
0161 struct simd_return_type_impl
0162 : std::enable_if<simd_condition<T1, T2>::value, batch<T2, A>>
0163 {
0164 };
0165
0166 template <class T2, class A>
0167 struct simd_return_type_impl<bool, T2, A>
0168 : std::enable_if<simd_condition<bool, T2>::value, batch_bool<T2, A>>
0169 {
0170 };
0171
0172 template <class T2, class A>
0173 struct simd_return_type_impl<bool, std::complex<T2>, A>
0174 : std::enable_if<simd_condition<bool, T2>::value, batch_bool<T2, A>>
0175 {
0176 };
0177
0178 template <class T1, class T2, class A>
0179 struct simd_return_type_impl<std::complex<T1>, T2, A>
0180 : std::enable_if<simd_condition<T1, T2>::value, batch<std::complex<T2>, A>>
0181 {
0182 };
0183
0184 template <class T1, class T2, class A>
0185 struct simd_return_type_impl<std::complex<T1>, std::complex<T2>, A>
0186 : std::enable_if<simd_condition<T1, T2>::value, batch<std::complex<T2>, A>>
0187 {
0188 };
0189
0190 #ifdef XSIMD_ENABLE_XTL_COMPLEX
0191 template <class T1, class T2, bool I3EC, class A>
0192 struct simd_return_type_impl<xtl::xcomplex<T1, T1, I3EC>, T2, A>
0193 : std::enable_if<simd_condition<T1, T2>::value, batch<std::complex<T2>, A>>
0194 {
0195 };
0196
0197 template <class T1, class T2, bool I3EC, class A>
0198 struct simd_return_type_impl<xtl::xcomplex<T1, T1, I3EC>, std::complex<T2>, A>
0199 : std::enable_if<simd_condition<T1, T2>::value, batch<std::complex<T2>, A>>
0200 {
0201 };
0202
0203 template <class T1, class T2, bool I3EC, class A>
0204 struct simd_return_type_impl<xtl::xcomplex<T1, T1, I3EC>, xtl::xcomplex<T2, T2, I3EC>, A>
0205 : std::enable_if<simd_condition<T1, T2>::value, batch<std::complex<T2>, A>>
0206 {
0207 };
0208
0209 template <class T1, class T2, bool I3EC, class A>
0210 struct simd_return_type_impl<std::complex<T1>, xtl::xcomplex<T2, T2, I3EC>, A>
0211 : std::enable_if<simd_condition<T1, T2>::value, batch<std::complex<T2>, A>>
0212 {
0213 };
0214 #endif
0215 }
0216
0217 template <class T1, class T2, class A = default_arch>
0218 using simd_return_type = typename detail::simd_return_type_impl<T1, T2, A>::type;
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228 template <class T>
0229 struct is_batch;
0230
0231 template <class T>
0232 struct is_batch : std::false_type
0233 {
0234 };
0235
0236 template <class T, class A>
0237 struct is_batch<batch<T, A>> : std::true_type
0238 {
0239 };
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 template <class T>
0251 struct is_batch_bool : std::false_type
0252 {
0253 };
0254
0255 template <class T, class A>
0256 struct is_batch_bool<batch_bool<T, A>> : std::true_type
0257 {
0258 };
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 template <class T>
0270 struct is_batch_complex : std::false_type
0271 {
0272 };
0273
0274 template <class T, class A>
0275 struct is_batch_complex<batch<std::complex<T>, A>> : std::true_type
0276 {
0277 };
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287 template <class T>
0288 struct scalar_type
0289 {
0290 using type = T;
0291 };
0292 template <class T, class A>
0293 struct scalar_type<batch<T, A>>
0294 {
0295 using type = T;
0296 };
0297
0298 template <class T>
0299 using scalar_type_t = typename scalar_type<T>::type;
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309 template <class T>
0310 struct mask_type
0311 {
0312 using type = bool;
0313 };
0314 template <class T, class A>
0315 struct mask_type<batch<T, A>>
0316 {
0317 using type = typename batch<T, A>::batch_bool_type;
0318 };
0319
0320 template <class T>
0321 using mask_type_t = typename mask_type<T>::type;
0322 }
0323
0324 #endif