File indexing completed on 2026-11-07 10:36:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef XSIMD_COMMON_LOGICAL_HPP
0013 #define XSIMD_COMMON_LOGICAL_HPP
0014
0015 #include "./xsimd_common_bit.hpp"
0016 #include "./xsimd_common_details.hpp"
0017
0018 #include <climits>
0019
0020 namespace xsimd
0021 {
0022
0023 namespace kernel
0024 {
0025
0026 using namespace types;
0027
0028
0029 template <class A, class T>
0030 XSIMD_INLINE size_t count(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0031 {
0032 return xsimd::detail::popcount(self.mask());
0033 }
0034
0035 template <class A, class T>
0036 XSIMD_INLINE size_t countl_zero(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0037 {
0038 constexpr size_t unused_bits = 64 - batch_bool<T, A>::size;
0039 constexpr uint64_t lower_mask = batch_bool<T, A>::size < 64 ? ((uint64_t)1 << (batch_bool<T, A>::size % 64)) - 1 : (uint64_t)-1;
0040 return xsimd::detail::countl_zero(self.mask() & lower_mask) - unused_bits;
0041 }
0042
0043 template <class A, class T>
0044 XSIMD_INLINE size_t countl_one(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0045 {
0046 constexpr size_t unused_bits = 64 - batch_bool<T, A>::size;
0047 constexpr uint64_t upper_mask = batch_bool<T, A>::size < 64 ? ~(((uint64_t)1 << (batch_bool<T, A>::size % 64)) - 1) : (uint64_t)0;
0048 return xsimd::detail::countl_one(self.mask() | upper_mask) - unused_bits;
0049 }
0050
0051 template <class A, class T>
0052 XSIMD_INLINE size_t countr_zero(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0053 {
0054 constexpr uint64_t stop = batch_bool<T, A>::size < 64 ? (uint64_t)1 << (batch_bool<T, A>::size % 64) : 0;
0055 return xsimd::detail::countr_zero(self.mask() | stop);
0056 }
0057
0058 template <class A, class T>
0059 XSIMD_INLINE size_t countr_one(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0060 {
0061 constexpr uint64_t stop = batch_bool<T, A>::size < 64 ? ~((uint64_t)1 << (batch_bool<T, A>::size % 64)) : (uint64_t)-1;
0062 return xsimd::detail::countr_one(self.mask() & stop);
0063 }
0064
0065
0066 template <class A, class T>
0067 XSIMD_INLINE batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<common>) noexcept
0068 {
0069 alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
0070
0071 for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
0072 buffer[i] = mask & (1ull << i);
0073 return batch_bool<T, A>::load_aligned(buffer);
0074 }
0075
0076
0077 template <class A, class T>
0078 XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0079 {
0080 return other <= self;
0081 }
0082
0083
0084 template <class A, class T>
0085 XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0086 {
0087 return other < self;
0088 }
0089
0090
0091 template <class A, class T>
0092 XSIMD_INLINE batch_bool<T, A> is_even(batch<T, A> const& self, requires_arch<common>) noexcept
0093 {
0094 return is_flint(self * T(0.5));
0095 }
0096
0097
0098 template <class A, class T>
0099 XSIMD_INLINE batch_bool<T, A> is_flint(batch<T, A> const& self, requires_arch<common>) noexcept
0100 {
0101 auto frac = select(isnan(self - self), constants::nan<batch<T, A>>(), self - trunc(self));
0102 return frac == T(0.);
0103 }
0104
0105
0106 template <class A, class T>
0107 XSIMD_INLINE batch_bool<T, A> is_odd(batch<T, A> const& self, requires_arch<common>) noexcept
0108 {
0109 return is_even(self - T(1.));
0110 }
0111
0112
0113 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0114 XSIMD_INLINE batch_bool<T, A> isinf(batch<T, A> const&, requires_arch<common>) noexcept
0115 {
0116 return batch_bool<T, A>(false);
0117 }
0118 template <class A>
0119 XSIMD_INLINE batch_bool<float, A> isinf(batch<float, A> const& self, requires_arch<common>) noexcept
0120 {
0121 #ifdef __FAST_MATH__
0122 (void)self;
0123 return { false };
0124 #else
0125 return abs(self) == std::numeric_limits<float>::infinity();
0126 #endif
0127 }
0128 template <class A>
0129 XSIMD_INLINE batch_bool<double, A> isinf(batch<double, A> const& self, requires_arch<common>) noexcept
0130 {
0131 #ifdef __FAST_MATH__
0132 (void)self;
0133 return { false };
0134 #else
0135 return abs(self) == std::numeric_limits<double>::infinity();
0136 #endif
0137 }
0138
0139
0140 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0141 XSIMD_INLINE batch_bool<T, A> isfinite(batch<T, A> const&, requires_arch<common>) noexcept
0142 {
0143 return batch_bool<T, A>(true);
0144 }
0145 template <class A>
0146 XSIMD_INLINE batch_bool<float, A> isfinite(batch<float, A> const& self, requires_arch<common>) noexcept
0147 {
0148 return (self - self) == 0.f;
0149 }
0150 template <class A>
0151 XSIMD_INLINE batch_bool<double, A> isfinite(batch<double, A> const& self, requires_arch<common>) noexcept
0152 {
0153 return (self - self) == 0.;
0154 }
0155
0156
0157 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0158 XSIMD_INLINE batch_bool<T, A> isnan(batch<T, A> const&, requires_arch<common>) noexcept
0159 {
0160 return batch_bool<T, A>(false);
0161 }
0162
0163
0164 template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0165 XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0166 {
0167 return (self < other) || (self == other);
0168 }
0169
0170
0171 template <class A, class T>
0172 XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0173 {
0174 return !(other == self);
0175 }
0176
0177
0178 template <class A, class T>
0179 XSIMD_INLINE batch<T, A> logical_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0180 {
0181 return detail::apply([](T x, T y) noexcept
0182 { return x && y; },
0183 self, other);
0184 }
0185
0186
0187 template <class A, class T>
0188 XSIMD_INLINE batch<T, A> logical_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0189 {
0190 return detail::apply([](T x, T y) noexcept
0191 { return x || y; },
0192 self, other);
0193 }
0194
0195
0196 template <class A, class T>
0197 XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0198 {
0199 alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
0200 self.store_aligned(buffer);
0201
0202 uint64_t res = 0;
0203 for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
0204 if (buffer[i])
0205 res |= 1ul << i;
0206 return res;
0207 }
0208
0209
0210 namespace detail
0211 {
0212 template <typename T, typename A>
0213 using is_batch_bool_register_same = std::is_same<typename batch_bool<T, A>::register_type, typename batch<T, A>::register_type>;
0214 }
0215
0216 template <class A, class T, std::enable_if_t<detail::is_batch_bool_register_same<T, A>::value, int> = 3>
0217 XSIMD_INLINE batch_bool<T, A> select(batch_bool<T, A> const& cond, batch_bool<T, A> const& true_br, batch_bool<T, A> const& false_br, requires_arch<common>)
0218 {
0219 using register_type = typename batch_bool<T, A>::register_type;
0220
0221 const auto true_v = batch<T, A> { static_cast<register_type>(true_br) };
0222 const auto false_v = batch<T, A> { static_cast<register_type>(false_br) };
0223 return batch_bool<T, A> { select(cond, true_v, false_v) };
0224 }
0225
0226 template <class A, class T, std::enable_if_t<!detail::is_batch_bool_register_same<T, A>::value, int> = 3>
0227 XSIMD_INLINE batch_bool<T, A> select(batch_bool<T, A> const& cond, batch_bool<T, A> const& true_br, batch_bool<T, A> const& false_br, requires_arch<common>)
0228 {
0229 return (true_br & cond) | (bitwise_andnot(false_br, cond));
0230 }
0231
0232 template <class A, class T, bool... Values>
0233 XSIMD_INLINE batch_bool<T, A> select(batch_bool_constant<T, A, Values...> const& cond, batch_bool<T, A> const& true_br, batch_bool<T, A> const& false_br, requires_arch<common>)
0234 {
0235 return (true_br & cond) | (false_br & ~cond);
0236 }
0237 }
0238 }
0239
0240 #endif