Skip to content

Commit

Permalink
if_else and related drive-by fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jfalcou committed Aug 20, 2023
1 parent f91e759 commit e69f191
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 11 deletions.
1 change: 1 addition & 0 deletions include/kyosu/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//======================================================================================================================
#include <kyosu/functions/abs.hpp>
#include <kyosu/functions/conj.hpp>
#include <kyosu/functions/if_else.hpp>
#include <kyosu/functions/ipart.hpp>
#include <kyosu/functions/jpart.hpp>
#include <kyosu/functions/kpart.hpp>
Expand Down
67 changes: 67 additions & 0 deletions include/kyosu/functions/if_else.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//======================================================================================================================
/*
Kyosu - Complex Without Complexes
Copyright : KYOSU Contributors & Maintainers
SPDX-License-Identifier: BSL-1.0
*/
//======================================================================================================================
#pragma once

#include <kyosu/details/invoke.hpp>

namespace kyosu::tags
{
struct callable_if_else : eve::elementwise
{
using callable_tag_type = callable_if_else;

KYOSU_FORCEINLINE
auto operator()(auto const& m, auto const& t, auto const& f) const noexcept -> decltype(eve::tag_invoke(*this,m,t,f))
{
return eve::tag_invoke(*this, m, t, f);
}

// template<typename... T>
// eve::unsupported_call<callable_if_else(T&&...)> operator()(T&&... x) const
// requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete;
};
}

namespace kyosu
{
//======================================================================================================================
//! @addtogroup functions
//! @{
//! @var if_else
//! @brief Select a value between two arguments based on a logical mask
//!
//! **Defined in Header**
//!
//! @code
//! #include <kyosu/functions.hpp>
//! @endcode
//!
//! @groupheader{Callable Signatures}
//!
//! @code
//! namespace kyosu
//! {
//! template<eve::value T, eve::value U, eve::value V>
//! constexpr auto if_else(T x, U, y, V z ) noexcept;
//! }
//! @endcode
//!
//! **Parameters**
//!
//! * `z` : Value to process.
//!
//! **Return value**
//!
//!
//! @groupheader{Example}
//!
//! @godbolt{doc/if_else.cpp}
//! @}
//======================================================================================================================
inline constexpr tags::callable_if_else if_else = {};
}
21 changes: 17 additions & 4 deletions include/kyosu/types/cayley_dickson.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <eve/module/core.hpp>
#include <kyosu/concepts.hpp>
#include <kyosu/functions.hpp>
#include <kyosu/types/traits.hpp>
#include <kyosu/types/impl/arithmetic.hpp>
#include <bit>

Expand Down Expand Up @@ -96,6 +97,19 @@ namespace kyosu
template<std::size_t I, typename T, unsigned int N>
constexpr auto get(cayley_dickson<T,N> const& c) noexcept { return kumi::get<I>(c.contents); }

//==================================================================================================================
// Tag invoke override for if_else - Outside so it can properly deals with the complicated parameters of if_else
//==================================================================================================================
template<typename T, typename F>
requires(concepts::cayley_dickson<T> || concepts::cayley_dickson<F>)
KYOSU_FORCEINLINE constexpr auto tag_invoke( eve::tag_of<kyosu::if_else> const& fn, auto, auto m
, T const& t, F const& f
) noexcept
-> decltype(_::dispatch(fn, m, t, f))
{
return _::dispatch(fn, m,t,f);
}

//==================================================================================================================
// Tag invoke override for parts extraction - Outside so they can see get<I>(c)
//==================================================================================================================
Expand Down Expand Up @@ -124,11 +138,11 @@ namespace kyosu
}

// TODO: Move to tag_invoke when EVE catch up on this front
template<typename Tag, concepts::cayley_dickson Z>
KYOSU_FORCEINLINE constexpr auto tagged_dispatch(Tag const&, eve::as<Z> const&) noexcept
template<typename Tag, eve::floating_scalar_value Type, unsigned int N>
KYOSU_FORCEINLINE constexpr auto tagged_dispatch(Tag const&, eve::as<cayley_dickson<Type,N>> const&) noexcept
{
eve::detail::callable_object<Tag> cst;
return Z(cst(eve::as<typename Z::value_type>{}));
return cayley_dickson<Type,N>( cst(eve::as<Type>{}) );
}

//====================================================================================================================
Expand Down Expand Up @@ -167,7 +181,6 @@ struct eve::supports_like<Wrapper,kyosu::cayley_dickson<T,N>>
};
#endif

#include <kyosu/types/traits.hpp>
#include <kyosu/types/impl/io.hpp>
#include <kyosu/types/impl/compounds.hpp>
#include <kyosu/types/impl/operators.hpp>
34 changes: 31 additions & 3 deletions include/kyosu/types/impl/arithmetic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,50 @@ namespace kyosu::_
{
template<concepts::cayley_dickson C>
KYOSU_FORCEINLINE constexpr
auto dispatch(eve::tag_of<conj> const&, C const& c) noexcept
auto dispatch(eve::tag_of<kyosu::conj> const&, C const& c) noexcept
{
return C{kumi::map_index([]<typename I>(I, auto const& m) { if constexpr(I::value>0) return -m; else return m;}, c)};
}

template<concepts::cayley_dickson C>
KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of<abs> const&, C const& c) noexcept
KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of<kyosu::abs> const&, C const& c) noexcept
{
return kumi::apply(eve::hypot, c);
}

template<concepts::cayley_dickson C>
KYOSU_FORCEINLINE constexpr
auto dispatch(eve::tag_of<sqr_abs> const&, C const& c) noexcept
auto dispatch(eve::tag_of<kyosu::sqr_abs> const&, C const& c) noexcept
{
auto squares = kumi::map([](auto const& e) { return e*e; }, c);
return kumi::sum( kumi::extract(squares,kumi::index<1>), get<0>(squares));
}

template<typename Mask, typename T, typename U>
KYOSU_FORCEINLINE constexpr
auto dispatch(eve::tag_of<kyosu::if_else> const&, Mask const& m, T const& t, U const& f) noexcept
{
if constexpr(concepts::cayley_dickson<T> && concepts::cayley_dickson<U>)
{
using type = as_cayley_dickson_t<T,U>;
auto parts = kumi::map([&](auto const& v, auto const& w) { return eve::if_else(m, v, w); }, t, f);

if constexpr(eve::simd_value<Mask>) return eve::as_wide_as_t<type,Mask>{parts};
else return type{parts};
}
else if constexpr(concepts::cayley_dickson<T> && !concepts::cayley_dickson<U>)
{
auto parts = kumi::map([&](auto const& v) { return eve::if_else(m, v, f); }, t);

if constexpr(eve::simd_value<Mask>) return eve::as_wide_as_t<T,Mask>{parts};
else return T{parts};
}
else if constexpr(!concepts::cayley_dickson<T> && concepts::cayley_dickson<U>)
{
auto parts = kumi::map([&](auto const& w) { return eve::if_else(m, t, w); }, f);

if constexpr(eve::simd_value<Mask>) return eve::as_wide_as_t<U,Mask>{parts};
else return U{parts};
}
}
}
17 changes: 13 additions & 4 deletions include/kyosu/types/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@
//======================================================================================================================
#pragma once

#include <bit>

namespace kyosu
{
template<eve::floating_scalar_value Type, unsigned int N>
requires(N> 1 && std::has_single_bit(N))
struct cayley_dickson;
}

namespace kyosu::_
{
// Force a type to be looked at as a wide so we can apply wide-like type presrving semantic in type computations
template<typename T> struct sema { using type = T; };
template<typename T> struct sema { using type = T; };
template<concepts::cayley_dickson T> struct sema<T> { using type = eve::wide<eve::underlying_type_t<T>>; };
template<typename T> using sema_t = typename sema<T>::type;
template<typename T> using sema_t = typename sema<T>::type;

// Convert a Base type to a potential wide if any appear in T...
template<typename Base, typename... T>
Expand Down Expand Up @@ -50,7 +59,7 @@ namespace kyosu
inline constexpr auto dimension_v<T> = eve::element_type_t<std::remove_cvref_t<T>>::static_size;

template<typename T> struct as_real { using type = T; };
template<typename T,unsigned int Dim> struct as_real<cayley_dickson<T,Dim>> { using type = T; };
template<typename T,unsigned int Dim> struct as_real<cayley_dickson<T,Dim>> { using type = T; };
template<typename T,typename N> struct as_real<eve::wide<T,N>>
{
using type = eve::wide<typename as_real<T>::type,N>;
Expand All @@ -68,7 +77,7 @@ namespace kyosu
struct as_cayley_dickson_n;

template<unsigned int Dim, typename... Ts>
requires( Dim > 1 &&requires(Ts... ts) { eve::add( std::declval<_::sema_t<Ts>>()...); } )
requires( Dim > 1 && requires(Ts... ts) { eve::add( std::declval<_::sema_t<Ts>>()...); } )
struct as_cayley_dickson_n<Dim,Ts...>
#if !defined(KYOSU_DOXYGEN_INVOKED)
: as_cayley_dickson_n<Dim, _::widen<decltype(eve::add( std::declval<_::sema_t<Ts>>()...)),Ts...>>
Expand Down

0 comments on commit e69f191

Please sign in to comment.