Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/xsimd/types/xsimd_batch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ namespace xsimd
static constexpr std::size_t size = sizeof(types::simd_register<T, A>) / sizeof(T); ///< Number of scalar elements in this batch.

using value_type = bool; ///< Type of the scalar elements within this batch.
using operand_type = T;
using arch_type = A; ///< SIMD Architecture abstracted by this batch.
using register_type = typename base_type::register_type; ///< SIMD register type abstracted by this batch.
using batch_type = batch<T, A>; ///< Associated batch type this batch represents logical operations for.
Expand Down
84 changes: 77 additions & 7 deletions include/xsimd/types/xsimd_batch_constant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#ifndef XSIMD_BATCH_CONSTANT_HPP
#define XSIMD_BATCH_CONSTANT_HPP

#include <cstddef>

#include "./xsimd_batch.hpp"
#include "./xsimd_utils.hpp"

Expand All @@ -31,6 +33,7 @@ namespace xsimd
using batch_type = batch_bool<T, A>;
static constexpr std::size_t size = sizeof...(Values);
using value_type = bool;
using operand_type = T;
static_assert(sizeof...(Values) == batch_type::size, "consistent batch size");

public:
Expand All @@ -44,7 +47,7 @@ namespace xsimd
*/
constexpr operator batch_type() const noexcept { return as_batch_bool(); }

constexpr bool get(size_t i) const noexcept
constexpr bool get(std::size_t i) const noexcept
{
return std::array<value_type, size> { { Values... } }[i];
}
Expand Down Expand Up @@ -76,7 +79,7 @@ namespace xsimd
constexpr bool operator()(bool x, bool y) const { return x ^ y; }
};

template <class F, class SelfPack, class OtherPack, size_t... Indices>
template <class F, class SelfPack, class OtherPack, std::size_t... Indices>
static constexpr batch_bool_constant<T, A, F()(std::tuple_element<Indices, SelfPack>::type::value, std::tuple_element<Indices, OtherPack>::type::value)...>
apply(detail::index_sequence<Indices...>)
{
Expand All @@ -88,7 +91,7 @@ namespace xsimd
-> decltype(apply<F, std::tuple<std::integral_constant<bool, Values>...>, std::tuple<std::integral_constant<bool, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>()))
{
static_assert(sizeof...(Values) == sizeof...(OtherValues), "compatible constant batches");
return apply<F, std::tuple<std::integral_constant<bool, Values>...>, std::tuple<std::integral_constant<bool, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>());
return {};
}

public:
Expand Down Expand Up @@ -148,13 +151,13 @@ namespace xsimd
/**
* @brief Get the @p i th element of this @p batch_constant
*/
constexpr T get(size_t i) const noexcept
constexpr T get(std::size_t i) const noexcept
{
return get(i, std::array<T, size> { Values... });
}

private:
constexpr T get(size_t i, std::array<T, size> const& values) const noexcept
constexpr T get(std::size_t i, std::array<T, size> const& values) const noexcept
{
return values[i];
}
Expand Down Expand Up @@ -191,8 +194,16 @@ namespace xsimd
{
constexpr T operator()(T x, T y) const { return x ^ y; }
};
struct binary_rshift
{
constexpr T operator()(T x, T y) const { return x >> y; }
};
struct binary_lshift
{
constexpr T operator()(T x, T y) const { return x << y; }
};

template <class F, class SelfPack, class OtherPack, size_t... Indices>
template <class F, class SelfPack, class OtherPack, std::size_t... Indices>
static constexpr batch_constant<T, A, F()(std::tuple_element<Indices, SelfPack>::type::value, std::tuple_element<Indices, OtherPack>::type::value)...>
apply(detail::index_sequence<Indices...>)
{
Expand All @@ -204,7 +215,7 @@ namespace xsimd
-> decltype(apply<F, std::tuple<std::integral_constant<T, Values>...>, std::tuple<std::integral_constant<T, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>()))
{
static_assert(sizeof...(Values) == sizeof...(OtherValues), "compatible constant batches");
return apply<F, std::tuple<std::integral_constant<T, Values>...>, std::tuple<std::integral_constant<T, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>());
return {};
}

public:
Expand All @@ -224,9 +235,68 @@ namespace xsimd
MAKE_BINARY_OP(&, binary_and)
MAKE_BINARY_OP(|, binary_or)
MAKE_BINARY_OP(^, binary_xor)
MAKE_BINARY_OP(<<, binary_lshift)
MAKE_BINARY_OP(>>, binary_rshift)

#undef MAKE_BINARY_OP

struct boolean_eq
{
constexpr bool operator()(T x, T y) const { return x == y; }
};
struct boolean_ne
{
constexpr bool operator()(T x, T y) const { return x != y; }
};
struct boolean_gt
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

@AntoinePrv AntoinePrv Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to but they are only constexpr since C++14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed!

constexpr bool operator()(T x, T y) const { return x > y; }
};
struct boolean_ge
{
constexpr bool operator()(T x, T y) const { return x >= y; }
};
struct boolean_lt
{
constexpr bool operator()(T x, T y) const { return x < y; }
};
struct boolean_le
{
constexpr bool operator()(T x, T y) const { return x <= y; }
};

template <class F, class SelfPack, class OtherPack, std::size_t... Indices>
static constexpr batch_bool_constant<T, A, F()(std::tuple_element<Indices, SelfPack>::type::value, std::tuple_element<Indices, OtherPack>::type::value)...>
apply_bool(detail::index_sequence<Indices...>)
{
return {};
}

template <class F, T... OtherValues>
static constexpr auto apply_bool(batch_constant<T, A, Values...>, batch_constant<T, A, OtherValues...>)
-> decltype(apply_bool<F, std::tuple<std::integral_constant<T, Values>...>, std::tuple<std::integral_constant<T, OtherValues>...>>(detail::make_index_sequence<sizeof...(Values)>()))
{
static_assert(sizeof...(Values) == sizeof...(OtherValues), "compatible constant batches");
return {};
}

#define MAKE_BINARY_BOOL_OP(OP, NAME) \
template <T... OtherValues> \
constexpr auto operator OP(batch_constant<T, A, OtherValues...> other) const \
-> decltype(apply_bool<NAME>(*this, other)) \
{ \
return {}; \
}

MAKE_BINARY_BOOL_OP(==, boolean_eq)
MAKE_BINARY_BOOL_OP(!=, boolean_ne)
MAKE_BINARY_BOOL_OP(<, boolean_lt)
MAKE_BINARY_BOOL_OP(<=, boolean_le)
MAKE_BINARY_BOOL_OP(>, boolean_gt)
MAKE_BINARY_BOOL_OP(>=, boolean_ge)

#undef MAKE_BINARY_BOOL_OP

constexpr batch_constant<T, A, (T)-Values...> operator-() const
{
return {};
Expand Down
32 changes: 32 additions & 0 deletions test/test_batch_constant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ struct constant_batch_test
constexpr auto n12_lxor_n3 = n12 ^ n3;
static_assert(std::is_same<decltype(n12_lxor_n3), decltype(n15)>::value, "n12 ^ n3 == n15");

constexpr auto n96 = xsimd::make_batch_constant<value_type, constant<96>, arch_type>();
constexpr auto n12_lshift_n3 = n12 << n3;
static_assert(std::is_same<decltype(n12_lshift_n3), decltype(n96)>::value, "n12 << n3 == n96");

constexpr auto n1 = xsimd::make_batch_constant<value_type, constant<1>, arch_type>();
constexpr auto n12_rshift_n3 = n12 >> n3;
static_assert(std::is_same<decltype(n12_rshift_n3), decltype(n1)>::value, "n12 >> n3 == n1");

constexpr auto n12_uadd = +n12;
static_assert(std::is_same<decltype(n12_uadd), decltype(n12)>::value, "+n12 == n12");

Expand All @@ -146,6 +154,30 @@ struct constant_batch_test
constexpr auto n12_usub = -n12;
constexpr auto n12_usub_ = xsimd::make_batch_constant<value_type, constant<(value_type)-12>, arch_type>();
static_assert(std::is_same<decltype(n12_usub), decltype(n12_usub_)>::value, "-n12 == n12_usub");

// comparison operators
using true_batch_type = decltype(xsimd::make_batch_bool_constant<value_type, true, arch_type>());
using false_batch_type = decltype(xsimd::make_batch_bool_constant<value_type, false, arch_type>());

static_assert(std::is_same<typename decltype(n12 == n12)::operand_type, typename decltype(n12)::value_type>::value, "same type");

static_assert(std::is_same<decltype(n12 == n12), true_batch_type>::value, "n12 == n12");
static_assert(std::is_same<decltype(n12 == n3), false_batch_type>::value, "n12 == n3");

static_assert(std::is_same<decltype(n12 != n12), false_batch_type>::value, "n12 != n12");
static_assert(std::is_same<decltype(n12 != n3), true_batch_type>::value, "n12 != n3");

static_assert(std::is_same<decltype(n12 < n12), false_batch_type>::value, "n12 < n12");
static_assert(std::is_same<decltype(n12 < n3), false_batch_type>::value, "n12 < n3");

static_assert(std::is_same<decltype(n12 > n12), false_batch_type>::value, "n12 > n12");
static_assert(std::is_same<decltype(n12 > n3), true_batch_type>::value, "n12 > n3");

static_assert(std::is_same<decltype(n12 <= n12), true_batch_type>::value, "n12 <= n12");
static_assert(std::is_same<decltype(n12 <= n3), false_batch_type>::value, "n12 <= n3");

static_assert(std::is_same<decltype(n12 >= n12), true_batch_type>::value, "n12 >= n12");
static_assert(std::is_same<decltype(n12 >= n3), true_batch_type>::value, "n12 >= n3");
}
};

Expand Down