File indexing completed on 2025-08-28 09:11:27
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef XSIMD_GENERIC_LOGICAL_HPP
0013 #define XSIMD_GENERIC_LOGICAL_HPP
0014
0015 #include "./xsimd_generic_details.hpp"
0016
0017 #include <climits>
0018
0019 namespace xsimd
0020 {
0021
0022 namespace kernel
0023 {
0024
0025 using namespace types;
0026
0027
0028 template <class A, class T>
0029 XSIMD_INLINE size_t count(batch_bool<T, A> const& self, requires_arch<generic>) noexcept
0030 {
0031 uint64_t m = self.mask();
0032 XSIMD_IF_CONSTEXPR(batch_bool<T, A>::size < 14)
0033 {
0034
0035 return (m * 0x200040008001ULL & 0x111111111111111ULL) % 0xf;
0036 }
0037 else
0038 {
0039 #if defined __has_builtin
0040 #if __has_builtin(__builtin_popcountg)
0041 #define builtin_popcount(v) __builtin_popcountg(v)
0042 #endif
0043 #endif
0044
0045 #ifdef builtin_popcount
0046 return builtin_popcount(m);
0047 #else
0048
0049
0050 XSIMD_IF_CONSTEXPR(batch_bool<T, A>::size <= 32)
0051 {
0052 uint32_t m32 = m;
0053
0054 m32 = m32 - ((m32 >> 1) & 0x55555555);
0055 m32 = (m32 & 0x33333333) + ((m32 >> 2) & 0x33333333);
0056 return (((m32 + (m32 >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
0057 }
0058 else
0059 {
0060
0061 m = m - ((m >> 1) & (uint64_t) ~(uint64_t)0 / 3);
0062 m = (m & (uint64_t) ~(uint64_t)0 / 15 * 3) + ((m >> 2) & (uint64_t) ~(uint64_t)0 / 15 * 3);
0063 m = (m + (m >> 4)) & (uint64_t) ~(uint64_t)0 / 255 * 15;
0064 return (m * ((uint64_t) ~(uint64_t)0 / 255)) >> (sizeof(uint64_t) - 1) * CHAR_BIT;
0065 }
0066 #endif
0067 }
0068 }
0069
0070
0071 template <class A, class T>
0072 XSIMD_INLINE batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<generic>) noexcept
0073 {
0074 alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
0075
0076
0077 for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
0078 buffer[i] = mask & (1ull << i);
0079 return batch_bool<T, A>::load_aligned(buffer);
0080 }
0081
0082
0083 template <class A, class T>
0084 XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
0085 {
0086 return other <= self;
0087 }
0088
0089
0090 template <class A, class T>
0091 XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
0092 {
0093 return other < self;
0094 }
0095
0096
0097 template <class A, class T>
0098 XSIMD_INLINE batch_bool<T, A> is_even(batch<T, A> const& self, requires_arch<generic>) noexcept
0099 {
0100 return is_flint(self * T(0.5));
0101 }
0102
0103
0104 template <class A, class T>
0105 XSIMD_INLINE batch_bool<T, A> is_flint(batch<T, A> const& self, requires_arch<generic>) noexcept
0106 {
0107 auto frac = select(isnan(self - self), constants::nan<batch<T, A>>(), self - trunc(self));
0108 return frac == T(0.);
0109 }
0110
0111
0112 template <class A, class T>
0113 XSIMD_INLINE batch_bool<T, A> is_odd(batch<T, A> const& self, requires_arch<generic>) noexcept
0114 {
0115 return is_even(self - T(1.));
0116 }
0117
0118
0119 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
0120 XSIMD_INLINE batch_bool<T, A> isinf(batch<T, A> const&, requires_arch<generic>) noexcept
0121 {
0122 return batch_bool<T, A>(false);
0123 }
0124 template <class A>
0125 XSIMD_INLINE batch_bool<float, A> isinf(batch<float, A> const& self, requires_arch<generic>) noexcept
0126 {
0127 return abs(self) == std::numeric_limits<float>::infinity();
0128 }
0129 template <class A>
0130 XSIMD_INLINE batch_bool<double, A> isinf(batch<double, A> const& self, requires_arch<generic>) noexcept
0131 {
0132 return abs(self) == std::numeric_limits<double>::infinity();
0133 }
0134
0135
0136 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
0137 XSIMD_INLINE batch_bool<T, A> isfinite(batch<T, A> const&, requires_arch<generic>) noexcept
0138 {
0139 return batch_bool<T, A>(true);
0140 }
0141 template <class A>
0142 XSIMD_INLINE batch_bool<float, A> isfinite(batch<float, A> const& self, requires_arch<generic>) noexcept
0143 {
0144 return (self - self) == 0.f;
0145 }
0146 template <class A>
0147 XSIMD_INLINE batch_bool<double, A> isfinite(batch<double, A> const& self, requires_arch<generic>) noexcept
0148 {
0149 return (self - self) == 0.;
0150 }
0151
0152
0153 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
0154 XSIMD_INLINE batch_bool<T, A> isnan(batch<T, A> const&, requires_arch<generic>) noexcept
0155 {
0156 return batch_bool<T, A>(false);
0157 }
0158
0159
0160 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
0161 XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
0162 {
0163 return (self < other) || (self == other);
0164 }
0165
0166
0167 template <class A, class T>
0168 XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
0169 {
0170 return !(other == self);
0171 }
0172
0173
0174 template <class A, class T>
0175 XSIMD_INLINE batch<T, A> logical_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
0176 {
0177 return detail::apply([](T x, T y) noexcept
0178 { return x && y; },
0179 self, other);
0180 }
0181
0182
0183 template <class A, class T>
0184 XSIMD_INLINE batch<T, A> logical_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
0185 {
0186 return detail::apply([](T x, T y) noexcept
0187 { return x || y; },
0188 self, other);
0189 }
0190
0191
0192 template <class A, class T>
0193 XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<generic>) noexcept
0194 {
0195 alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
0196 self.store_aligned(buffer);
0197
0198
0199 uint64_t res = 0;
0200 for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
0201 if (buffer[i])
0202 res |= 1ul << i;
0203 return res;
0204 }
0205 }
0206 }
0207
0208 #endif