diff --git a/include/xsimd/arch/generic/xsimd_generic_logical.hpp b/include/xsimd/arch/generic/xsimd_generic_logical.hpp index 1a04c432e..ce5389d3a 100644 --- a/include/xsimd/arch/generic/xsimd_generic_logical.hpp +++ b/include/xsimd/arch/generic/xsimd_generic_logical.hpp @@ -77,6 +77,18 @@ namespace xsimd { template batch_bool neq(batch const& self, batch const& other, requires_arch) { return !(other == self); } + + // logical_and + template + batch logical_and(batch const& self, batch const& other, requires_arch) { + return detail::apply([](T x, T y) { return x && y;}, self, other); + } + + // logical_or + template + batch logical_or(batch const& self, batch const& other, requires_arch) { + return detail::apply([](T x, T y) { return x || y;}, self, other); + } } } diff --git a/include/xsimd/types/xsimd_batch.hpp b/include/xsimd/types/xsimd_batch.hpp index e5210ca37..f322805b3 100644 --- a/include/xsimd/types/xsimd_batch.hpp +++ b/include/xsimd/types/xsimd_batch.hpp @@ -124,6 +124,14 @@ struct batch : types::simd_register { return batch(self) <<= other; } + friend batch operator&&(batch const& self, batch const& other) { + return batch(self).logical_and(other); + } + + friend batch operator||(batch const& self, batch const& other) { + return batch(self).logical_or(other); + } + // Update operators batch& operator+=(batch const& other); batch& operator-=(batch const& other); @@ -147,6 +155,9 @@ struct batch : types::simd_register { private: template batch(T const* data, detail::index_sequence); + + batch logical_and(batch const& other) const; + batch logical_or(batch const& other) const; }; template @@ -431,6 +442,16 @@ batch_bool batch::operator>(batch const& other) const { return template batch_bool batch::operator<(batch const& other) const { return kernel::lt(*this, other, A{}); } +template +batch batch::logical_and(batch const& other) const { + return kernel::logical_and(*this, other, A()); +} + +template +batch batch::logical_or(batch const& other) const { + return kernel::logical_or(*this, other, A()); +} + template batch& batch::operator+=(batch const& other) { return *this = kernel::add(*this, other, A{}); } diff --git a/test/test_batch.cpp b/test/test_batch.cpp index 3889450a0..91091b89f 100644 --- a/test/test_batch.cpp +++ b/test/test_batch.cpp @@ -408,6 +408,42 @@ class batch_test : public testing::Test } } + void test_logical() const + { + // batch && batch + { + array_type expected; + std::transform(lhs.cbegin(), lhs.cend(), rhs.cbegin(), expected.begin(), std::logical_and()); + batch_type res = batch_lhs() && batch_rhs(); + EXPECT_BATCH_EQ(res, expected) << print_function_name("batch && batch"); + } + // batch && scalar + { + array_type expected; + std::transform(lhs.cbegin(), lhs.cend(), expected.begin(), std::bind(std::logical_and(), _1, scalar)); + batch_type lres = batch_lhs() && scalar; + EXPECT_BATCH_EQ(lres, expected) << print_function_name("batch && scalar"); + batch_type rres = scalar && batch_lhs(); + EXPECT_BATCH_EQ(rres, expected) << print_function_name("scalar && batch"); + } + // batch || batch + { + array_type expected; + std::transform(lhs.cbegin(), lhs.cend(), rhs.cbegin(), expected.begin(), std::logical_or()); + batch_type res = batch_lhs() || batch_rhs(); + EXPECT_BATCH_EQ(res, expected) << print_function_name("batch && batch"); + } + // batch || scalar + { + array_type expected; + std::transform(lhs.cbegin(), lhs.cend(), expected.begin(), std::bind(std::logical_or(), _1, scalar)); + batch_type lres = batch_lhs() || scalar; + EXPECT_BATCH_EQ(lres, expected) << print_function_name("batch || scalar"); + batch_type rres = scalar || batch_lhs(); + EXPECT_BATCH_EQ(rres, expected) << print_function_name("scalar || batch"); + } + } + void test_min_max() const { // min @@ -688,6 +724,10 @@ TYPED_TEST(batch_test, comparison) { this->test_comparison(); } +TYPED_TEST(batch_test, logical) +{ + this->test_logical(); +} TYPED_TEST(batch_test, min_max) {