Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
26 changes: 26 additions & 0 deletions include/xsimd/arch/generic/xsimd_generic_memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,32 @@ namespace xsimd

using namespace types;

// broadcast
namespace detail
{
template <class T, class A>
struct broadcaster
{
using return_type = batch<T, A>;

static XSIMD_INLINE return_type run(T v) noexcept
{
return return_type::broadcast(v);
}
};

template <class A>
struct broadcaster<bool, A>
{
using return_type = batch_bool<xsimd::as_unsigned_integer_t<bool>, A>;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not quite sure about that. You're creating a batch_bool out of bool, which looks fine at first glance, but a batch_bool neeads to know what kind of type it's operating one, why choosing xsimd::as_unsigned_integer_t<bool> ? The user has no way to specify the actual type...

Copy link
Member Author

@JohanMabille JohanMabille Feb 25, 2025

Choose a reason for hiding this comment

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

This method is called only when you want to operate on batches of boolean values (the old batch<bool> that we removed), therefore the underlying type does not really matter. I chose uint8_t so that we can operate on a maximum number of boolean values in the batch_bool.

If you need a specific underlying type for the batch_bool, then you have to use broadcast_as instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok. I think we need to document that somewhere, either in the doxygen comment or by moving the specializatin at the API level so that the difference in behavior is clear when passing a bool to xsimd::broadcast. Bonus point if you mention xsimd::broadcast_as there ;-)

Copy link
Member Author

@JohanMabille JohanMabille Feb 25, 2025

Choose a reason for hiding this comment

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

Moving the specialization at the API level is what I did initially (where it actually becomes an overload, since we cannot partially specialize functions). The issue is that the overload as only one template parameter, and with the default value of the first overload, the compiler does not pick the right overload, leading to compilation issues for regular cases (i.e. not bool). I'll add more documentation.

Copy link
Contributor

Choose a reason for hiding this comment

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

gotcha


static XSIMD_INLINE return_type run(bool b) noexcept
{
return return_type(b);
}
};
}

// compress
namespace detail
{
Expand Down
4 changes: 2 additions & 2 deletions include/xsimd/types/xsimd_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,10 +491,10 @@ namespace xsimd
* @return a new batch instance
*/
template <class T, class A = default_arch>
XSIMD_INLINE batch<T, A> broadcast(T v) noexcept
XSIMD_INLINE typename kernel::detail::broadcaster<T, A>::return_type broadcast(T v) noexcept
{
detail::static_check_supported_config<T, A>();
return batch<T, A>::broadcast(v);
return kernel::detail::broadcaster<T, A>::run(v);
}

/**
Expand Down
5 changes: 5 additions & 0 deletions include/xsimd/types/xsimd_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ namespace xsimd
"usage of batch type with unsupported type");
};

template <class A>
struct static_check_supported_config_emitter<bool, A> : static_check_supported_config_emitter<xsimd::as_unsigned_integer_t<bool>, A>
{
};

template <class T, class A>
struct static_check_supported_config_emitter<std::complex<T>, A> : static_check_supported_config_emitter<T, A>
{
Expand Down
6 changes: 6 additions & 0 deletions include/xsimd/types/xsimd_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ namespace xsimd
{
};

template <>
struct as_unsigned_integer<bool>
{
using type = uint8_t;
};

template <>
struct as_unsigned_integer<float>
{
Expand Down
11 changes: 11 additions & 0 deletions test/test_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct xsimd_api_test
{
using batch_type = B;
using batch_bool_type = typename B::batch_bool_type;
using arch_type = typename B::arch_type;
using value_type = typename B::value_type;
static constexpr size_t size = B::size;
using array_type = std::array<value_type, size>;
Expand Down Expand Up @@ -100,6 +101,7 @@ struct xsimd_api_test

void test_set()
{
test_set_bool("set bool");
test_set_impl<int8_t>("set int8_t");
test_set_impl<uint8_t>("set uint8_t");
test_set_impl<int16_t>("set int16_t");
Expand Down Expand Up @@ -171,6 +173,15 @@ struct xsimd_api_test
CHECK_BATCH_EQ(res, expected);
}

void test_set_bool(const std::string& name)
{
bool v = true;
xsimd::batch_bool<uint8_t, arch_type> expected(v);
xsimd::batch_bool<uint8_t, arch_type> res = xsimd::broadcast(v);
INFO(name);
CHECK_BATCH_EQ(res, expected);
}

template <class V>
void init_test_vector(V& vec)
{
Expand Down
Loading