diff --git a/include/kyosu/functions.hpp b/include/kyosu/functions.hpp index 9f656b78..eef42653 100644 --- a/include/kyosu/functions.hpp +++ b/include/kyosu/functions.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/include/kyosu/functions/convert.hpp b/include/kyosu/functions/convert.hpp new file mode 100644 index 00000000..a36c9378 --- /dev/null +++ b/include/kyosu/functions/convert.hpp @@ -0,0 +1,76 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_convert : eve::elementwise + { + using callable_tag_type = callable_convert; + + KYOSU_DEFERS_CALLABLE(convert_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, eve::ordered_value auto const& v, eve::as const& tgt) noexcept + { + return eve::convert(v,tgt); + } + + template + KYOSU_FORCEINLINE + auto operator()(auto const& v, eve::as const& tgt) const noexcept -> decltype(eve::tag_invoke(*this,v,tgt)) + { + return eve::tag_invoke(*this, v, tgt); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var convert +//! @brief Select a value between two arguments based on a logical mask +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template +//! constexpr auto convert(T x, U, y, V z ) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/convert.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_convert convert = {}; +} diff --git a/include/kyosu/types/cayley_dickson.hpp b/include/kyosu/types/cayley_dickson.hpp index 4910c2c5..69487e50 100644 --- a/include/kyosu/types/cayley_dickson.hpp +++ b/include/kyosu/types/cayley_dickson.hpp @@ -139,6 +139,16 @@ namespace kyosu return _::dispatch(fn, m,t,f); } + template + requires( eve::scalar_value ) + KYOSU_FORCEINLINE + constexpr auto tag_invoke( eve::tag_of const& f, auto, C const& c, eve::as const& tgt) noexcept + -> decltype(_::dispatch(f, c, tgt)) + { + return _::dispatch(f, c, tgt); + } + + //================================================================================================================== // Tag invoke override for parts extraction - Outside so they can see get(c) //================================================================================================================== @@ -204,7 +214,7 @@ struct std::tuple_element> template struct eve::supports_like> : std::bool_constant< kyosu::concepts::cayley_dickson - || std::same_as> + || std::same_as> || plain_scalar_value > { diff --git a/include/kyosu/types/impl/arithmetic.hpp b/include/kyosu/types/impl/arithmetic.hpp index 9de796bd..66dd6695 100644 --- a/include/kyosu/types/impl/arithmetic.hpp +++ b/include/kyosu/types/impl/arithmetic.hpp @@ -136,7 +136,7 @@ namespace kyosu::_ { using r_t = as_cayley_dickson_t; return r_t{kumi::map([&t](auto const& e, auto const & f) { return eve::lerp(e, f, t); }, c0, c1)}; - } + } template KYOSU_FORCEINLINE constexpr @@ -174,5 +174,20 @@ namespace kyosu::_ auto dispatch(eve::tag_of const&, C c) noexcept { return conj(c)/sqr_abs(c); - } + } + template + requires(dimension_v <= dimension_v) + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C0 const & c, eve::as const & tgt) noexcept + { + using type = eve::as_wide_as_t; + + if constexpr(std::same_as,C1>) return c; + else if constexpr(dimension_v == 1ULL) return type{c}; + else + { + using u_t = eve::underlying_type_t; + return kumi::apply([](auto const&... e) { return type{kyosu::convert(e, eve::as{})...}; }, c); + } + } } diff --git a/include/kyosu/types/impl/operators.hpp b/include/kyosu/types/impl/operators.hpp index a91ba2cd..68bbfced 100644 --- a/include/kyosu/types/impl/operators.hpp +++ b/include/kyosu/types/impl/operators.hpp @@ -42,9 +42,10 @@ namespace kyosu /// Returns the sum of a Caley-dickson value and a real value in any order template requires(concepts::cayley_dickson || concepts::cayley_dickson) - as_cayley_dickson_t operator+(T1 const& a, T2 const& b) noexcept + auto operator+(T1 const& a, T2 const& b) noexcept -> as_cayley_dickson_t { - as_cayley_dickson_t that{a}; + using type = as_cayley_dickson_t; + type that{kyosu::convert(a,eve::as>())}; return that += b; } @@ -53,7 +54,8 @@ namespace kyosu requires(concepts::cayley_dickson || concepts::cayley_dickson) as_cayley_dickson_t operator-(T1 const& a, T2 const& b) noexcept { - as_cayley_dickson_t that{a}; + using type = as_cayley_dickson_t; + type that{kyosu::convert(a,eve::as>())}; return that -= b; } @@ -62,7 +64,8 @@ namespace kyosu requires(concepts::cayley_dickson && concepts::cayley_dickson) as_cayley_dickson_t operator*(T1 const& a, T2 const& b) noexcept { - as_cayley_dickson_t that{a}; + using type = as_cayley_dickson_t; + type that{kyosu::convert(a,eve::as>())}; return that *= b; } @@ -73,12 +76,14 @@ namespace kyosu // This is ok as the non cayley-dickson type is a scalar if constexpr(concepts::cayley_dickson) { - as_cayley_dickson_t that{a}; + using type = as_cayley_dickson_t; + type that{kyosu::convert(a,eve::as>())}; return that *= b; } else { - as_cayley_dickson_t that{b}; + using type = as_cayley_dickson_t; + type that{kyosu::convert(b,eve::as>())}; return that *= a; } } @@ -88,7 +93,8 @@ namespace kyosu requires(concepts::cayley_dickson || concepts::cayley_dickson) as_cayley_dickson_t operator/(T1 const& a, T2 const& b) noexcept { - as_cayley_dickson_t that{a}; + using type = as_cayley_dickson_t; + type that{kyosu::convert(a,eve::as>())}; return that /= b; } diff --git a/include/kyosu/types/traits.hpp b/include/kyosu/types/traits.hpp index 5ce85dc8..161f4ae9 100644 --- a/include/kyosu/types/traits.hpp +++ b/include/kyosu/types/traits.hpp @@ -93,12 +93,7 @@ namespace kyosu template requires( Dim > 1 && !requires(Ts... ts) { eve::add( std::declval<_::sema_t>()...); } ) - struct as_cayley_dickson_n - { - static_assert ( requires(Ts... ts) { eve::add( std::declval<_::sema_t>()...); } - , "[KYOSU] - STATIC ASSERT: Incompatible types in type resolution" - ); - }; + struct as_cayley_dickson_n {}; template requires(Dim > 1)