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
8 changes: 7 additions & 1 deletion docs/source/api/type_traits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ Type Traits
===========

`xsimd` provides a few type traits to interact with scalar and batch types in an
uniformeous manner.
uniform manner.


Combined traits:

+---------------------------------------+----------------------------------------------------+
| :cpp:class:`batch_traits` | batch types and proprties |
+---------------------------------------+----------------------------------------------------+

Type check:

+---------------------------------------+----------------------------------------------------+
Expand Down
29 changes: 29 additions & 0 deletions include/xsimd/arch/common/xsimd_common_logical.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,35 @@ namespace xsimd
res |= 1ul << i;
return res;
}

// select
namespace detail
{
template <typename T, typename A>
using is_batch_bool_register_same = std::is_same<typename batch_bool<T, A>::register_type, typename batch<T, A>::register_type>;
}

template <class A, class T, typename std::enable_if<detail::is_batch_bool_register_same<T, A>::value, int>::type = 3>
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>)
{
using register_type = typename batch_bool<T, A>::register_type;
// Do not cast, but rather reinterpret the masks as batches.
const auto true_v = batch<T, A> { static_cast<register_type>(true_br) };
const auto false_v = batch<T, A> { static_cast<register_type>(false_br) };
return batch_bool<T, A> { select(cond, true_v, false_v) };
}

template <class A, class T, typename std::enable_if<!detail::is_batch_bool_register_same<T, A>::value, int>::type = 3>
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>)
{
return (true_br & cond) | (bitwise_andnot(false_br, cond));
}

template <class A, class T, bool... Values>
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>)
{
return (true_br & cond) | (false_br & ~cond);
}
}
}

Expand Down
62 changes: 19 additions & 43 deletions include/xsimd/arch/xsimd_scalar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,53 +83,16 @@ namespace xsimd
using std::tgamma;
using std::trunc;

XSIMD_INLINE signed char abs(signed char v)
template <typename T>
XSIMD_INLINE constexpr typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, T>::type
abs(T v) noexcept
{
return v < 0 ? -v : v;
}

namespace detail
{
// Use templated type here to prevent automatic instantiation that may
// ends up in a warning
template <typename char_type>
XSIMD_INLINE char abs(char_type v, std::true_type)
{
return v;
}
template <typename char_type>
XSIMD_INLINE char abs(char_type v, std::false_type)
{
return v < 0 ? -v : v;
}
}

XSIMD_INLINE char abs(char v)
{
return detail::abs(v, std::is_unsigned<char>::type {});
}

XSIMD_INLINE short abs(short v)
{
return v < 0 ? -v : v;
}
XSIMD_INLINE unsigned char abs(unsigned char v)
{
return v;
}
XSIMD_INLINE unsigned short abs(unsigned short v)
{
return v;
}
XSIMD_INLINE unsigned int abs(unsigned int v)
{
return v;
}
XSIMD_INLINE unsigned long abs(unsigned long v)
{
return v;
}
XSIMD_INLINE unsigned long long abs(unsigned long long v)
template <typename T>
XSIMD_INLINE constexpr typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type
abs(T v) noexcept
{
return v;
}
Expand Down Expand Up @@ -1235,6 +1198,19 @@ namespace xsimd
{
return cond ? true_br : false_br;
}

template <class T>
XSIMD_INLINE constexpr bool batch_bool_cast(bool b) noexcept
{
return b;
}

template <class T_out, class T_in>
XSIMD_INLINE constexpr T_out batch_cast(T_in const& val) noexcept
{
static_assert(!std::is_same<T_out, bool>::value, "cannot convert to bool, use !x or x != 0");
return static_cast<T_out>(val);
}
}

#endif
42 changes: 42 additions & 0 deletions include/xsimd/types/xsimd_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2099,6 +2099,27 @@ namespace xsimd
return kernel::select<A>(cond, true_br, false_br, A {});
}

/**
* @ingroup batch_bool_logical
*
* Ternary operator for conditions: selects values from the batches \c true_br or \c false_br
* depending on the boolean values in the constant batch \c cond. Equivalent to
* \code{.cpp}
* for(std::size_t i = 0; i < N; ++i)
* res[i] = cond[i] ? true_br[i] : false_br[i];
* \endcode
* @param cond batch condition.
* @param true_br batch values for truthy condition.
* @param false_br batch value for falsy condition.
* @return the result of the selection.
*/
template <class T, class A>
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) noexcept
{
detail::static_check_supported_config<T, A>();
return kernel::select<A>(cond, true_br, false_br, A {});
}

/**
* @ingroup batch_cond
*
Expand Down Expand Up @@ -2141,6 +2162,27 @@ namespace xsimd
return kernel::select<A>(cond, true_br, false_br, A {});
}

/**
* @ingroup batch_cond
*
* Ternary operator for mask batches: selects values from the masks \c true_br or \c false_br
* depending on the boolean values in the constant batch \c cond. Equivalent to
* \code{.cpp}
* for(std::size_t i = 0; i < N; ++i)
* res[i] = cond[i] ? true_br[i] : false_br[i];
* \endcode
* @param cond constant batch condition.
* @param true_br batch values for truthy condition.
* @param false_br batch value for falsy condition.
* @return the result of the selection.
*/
template <class T, class A, bool... Values>
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) noexcept
{
detail::static_check_supported_config<T, A>();
return kernel::select<A>(cond, true_br, false_br, A {});
}

/**
* @ingroup batch_data_transfer
*
Expand Down
115 changes: 89 additions & 26 deletions include/xsimd/types/xsimd_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,59 +233,133 @@ namespace xsimd
/**
* @ingroup batch_traits
*
* type traits that inherits from @c std::true_type for @c batch<...> types and from
* @c std::false_type otherwise.
* type traits that provide information about a batch or scalar type.
*
* @tparam T type to analyze.
*/

template <class T>
struct is_batch;
struct batch_traits
{
using scalar_type = T; ///< T if scalar, or type of the scalar element for the batch T.
using mask_type = bool; ///< Mask type for T: bool for scalars, or batch_bool for batch types.

static constexpr bool is_batch = false; ///< True if T is @c batch<...>.
static constexpr bool is_batch_bool = false; ///< True if T is @c batch_bool<...>.
static constexpr bool is_any_batch = false; ///< True if T is @c batch<...> or @c batch_bool<...>.
static constexpr bool is_complex = detail::is_complex<T>::value; ///< True if T is complex or a batch of complex values.
};

#if __cplusplus < 201703L
template <class T>
constexpr bool batch_traits<T>::is_batch;
template <class T>
struct is_batch : std::false_type
constexpr bool batch_traits<T>::is_batch_bool;
template <class T>
constexpr bool batch_traits<T>::is_any_batch;
template <class T>
constexpr bool batch_traits<T>::is_complex;
#endif

template <class T, class A>
struct batch_traits<batch<T, A>>
{
using scalar_type = T;
using mask_type = typename batch<T, A>::batch_bool_type;

static constexpr bool is_batch = true;
static constexpr bool is_batch_bool = false;
static constexpr bool is_any_batch = true;
static constexpr bool is_complex = detail::is_complex<T>::value;
};

#if __cplusplus < 201703L
template <class T, class A>
constexpr bool batch_traits<batch<T, A>>::is_batch;
template <class T, class A>
constexpr bool batch_traits<batch<T, A>>::is_batch_bool;
template <class T, class A>
constexpr bool batch_traits<batch<T, A>>::is_any_batch;
template <class T, class A>
constexpr bool batch_traits<batch<T, A>>::is_complex;
#endif

template <class T, class A>
struct is_batch<batch<T, A>> : std::true_type
struct batch_traits<batch_bool<T, A>>
{
using scalar_type = bool;
using mask_type = batch_bool<T, A>;

static constexpr bool is_batch = false;
static constexpr bool is_batch_bool = true;
static constexpr bool is_any_batch = true;
static constexpr bool is_complex = false;
};

#if __cplusplus < 201703L
template <class T, class A>
constexpr bool batch_traits<batch_bool<T, A>>::is_batch;
template <class T, class A>
constexpr bool batch_traits<batch_bool<T, A>>::is_batch_bool;
template <class T, class A>
constexpr bool batch_traits<batch_bool<T, A>>::is_any_batch;
template <class T, class A>
constexpr bool batch_traits<batch_bool<T, A>>::is_complex;
#endif

/**
* @ingroup batch_traits
*
* type traits that inherits from @c std::true_type for @c batch_bool<...> types and from
* type traits that inherits from @c std::true_type for @c batch<...> types and from
* @c std::false_type otherwise.
*
* @tparam T type to analyze.
*/

template <class T>
struct is_batch_bool : std::false_type
struct is_batch : std::integral_constant<bool, batch_traits<T>::is_batch>
{
};

template <class T, class A>
struct is_batch_bool<batch_bool<T, A>> : std::true_type
/**
* @ingroup batch_traits
*
* type traits that inherits from @c std::true_type for @c batch_bool<...> types and from
* @c std::false_type otherwise.
*
* @tparam T type to analyze.
*/

template <class T>
struct is_batch_bool : std::integral_constant<bool, batch_traits<T>::is_batch_bool>
{
};

/**
* @ingroup batch_traits
*
* type traits that inherits from @c std::true_type for @c batch<std::complex<...>>
* type traits that inherits from @c std::true_type for @c batch<...> or batch_bool<...>
* types and from @c std::false_type otherwise.
*
* @tparam T type to analyze.
*/

template <class T>
struct is_batch_complex : std::false_type
struct is_any_batch : std::integral_constant<bool, batch_traits<T>::is_any_batch>
{
};

template <class T, class A>
struct is_batch_complex<batch<std::complex<T>, A>> : std::true_type
/**
* @ingroup batch_traits
*
* type traits that inherits from @c std::true_type for @c batch<std::complex<...>>
* types and from @c std::false_type otherwise.
*
* @tparam T type to analyze.
*/

template <class T>
struct is_batch_complex : std::integral_constant<bool, batch_traits<T>::is_batch && batch_traits<T>::is_complex>
{
};

Expand All @@ -300,12 +374,7 @@ namespace xsimd
template <class T>
struct scalar_type
{
using type = T;
};
template <class T, class A>
struct scalar_type<batch<T, A>>
{
using type = T;
using type = typename batch_traits<T>::scalar_type;
};

template <class T>
Expand All @@ -322,12 +391,7 @@ namespace xsimd
template <class T>
struct mask_type
{
using type = bool;
};
template <class T, class A>
struct mask_type<batch<T, A>>
{
using type = typename batch<T, A>::batch_bool_type;
using type = typename batch_traits<T>::mask_type;
};

template <class T>
Expand Down Expand Up @@ -364,7 +428,6 @@ namespace xsimd
}
template <typename T>
using widen_t = typename detail::widen<T>::type;

}

#endif
3 changes: 3 additions & 0 deletions test/test_batch_cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ struct batch_cast_test
T_out scalar_ref = static_cast<T_out>(in_test_value);
T_out scalar_res = res.get(0);
CHECK_SCALAR_EQ(scalar_ref, scalar_res);
CHECK_SCALAR_EQ(scalar_ref, xsimd::batch_cast<T_out>(in_test_value));
}
}

Expand All @@ -356,11 +357,13 @@ struct batch_cast_test
B_common_out all_true_res = xsimd::batch_bool_cast<T_out>(all_true_in);
INFO(name);
CHECK_SCALAR_EQ(all_true_res.get(0), true);
CHECK_SCALAR_EQ(xsimd::batch_bool_cast<B_out>(true), true);

B_common_in all_false_in(false);
B_common_out all_false_res = xsimd::batch_bool_cast<T_out>(all_false_in);
INFO(name);
CHECK_SCALAR_EQ(all_false_res.get(0), false);
CHECK_SCALAR_EQ(xsimd::batch_bool_cast<B_out>(false), false);
}
};

Expand Down
Loading