1919#include < cmath>
2020#include < complex>
2121#include < type_traits>
22+ #include < utility>
2223
2324#include < xtl/xcomplex.hpp>
2425#include < xtl/xmasked_value.hpp>
@@ -595,6 +596,44 @@ namespace xt
595596 {
596597 return static_cast <bool >(value.visible ());
597598 }
599+
600+ template <class ... Args>
601+ inline constexpr bool has_masked_value_v = (xtl::is_xmasked_value<std::decay_t <Args>>::value || ...);
602+
603+ template <class T >
604+ using masked_data_type_t = std::decay_t <decltype (masked_data(std::declval<const T&>()))>;
605+
606+ template <class ... Args>
607+ using masked_common_value_type_t = xtl::promote_type_t <masked_data_type_t <Args>...>;
608+
609+ template <class T >
610+ using masked_return_type_t = xtl::xmasked_value<T, bool >;
611+
612+ template <class ... Args>
613+ constexpr bool all_masked_visible (const Args&... args) noexcept
614+ {
615+ return (masked_visible (args) && ...);
616+ }
617+
618+ template <class T >
619+ constexpr auto hidden_masked_value () noexcept -> masked_return_type_t<T>
620+ {
621+ return masked_return_type_t <T>(T (0 ), false );
622+ }
623+
624+ template <class Result , class F , class ... Args>
625+ constexpr auto masked_map (F&& function, const Args&... args) -> masked_return_type_t<Result>
626+ {
627+ if (all_masked_visible (args...))
628+ {
629+ return masked_return_type_t <Result>(
630+ static_cast <Result>(std::forward<F>(function)(masked_data (args)...)),
631+ true
632+ );
633+ }
634+
635+ return hidden_masked_value<Result>();
636+ }
598637 }
599638
600639 template <class T = void >
@@ -603,25 +642,17 @@ namespace xt
603642 template <class A1 , class A2 >
604643 constexpr auto operator ()(const A1& t1, const A2& t2) const noexcept
605644 {
606- if constexpr (xtl::is_xmasked_value<std:: decay_t <A1>>::value || xtl::is_xmasked_value<std:: decay_t < A2>>::value )
645+ if constexpr (detail::has_masked_value_v<A1, A2>)
607646 {
608- using value_type = xtl::promote_type_t <
609- std::decay_t <decltype (detail::masked_data (t1))>,
610- std::decay_t <decltype (detail::masked_data (t2))>>;
611- using return_type = xtl::xmasked_value<value_type, bool >;
612-
613- if (detail::masked_visible (t1) && detail::masked_visible (t2))
614- {
615- return return_type (
616- static_cast <value_type>(
617- detail::masked_data (t1) < detail::masked_data (t2) ? detail::masked_data (t1)
618- : detail::masked_data (t2)
619- ),
620- true
621- );
622- }
623-
624- return return_type (value_type (0 ), false );
647+ using value_type = detail::masked_common_value_type_t <A1, A2>;
648+ return detail::masked_map<value_type>(
649+ [](const auto & lhs, const auto & rhs)
650+ {
651+ return lhs < rhs ? lhs : rhs;
652+ },
653+ t1,
654+ t2
655+ );
625656 }
626657 else
627658 {
@@ -642,25 +673,17 @@ namespace xt
642673 template <class A1 , class A2 >
643674 constexpr auto operator ()(const A1& t1, const A2& t2) const noexcept
644675 {
645- if constexpr (xtl::is_xmasked_value<std:: decay_t <A1>>::value || xtl::is_xmasked_value<std:: decay_t < A2>>::value )
676+ if constexpr (detail::has_masked_value_v<A1, A2>)
646677 {
647- using value_type = xtl::promote_type_t <
648- std::decay_t <decltype (detail::masked_data (t1))>,
649- std::decay_t <decltype (detail::masked_data (t2))>>;
650- using return_type = xtl::xmasked_value<value_type, bool >;
651-
652- if (detail::masked_visible (t1) && detail::masked_visible (t2))
653- {
654- return return_type (
655- static_cast <value_type>(
656- detail::masked_data (t1) > detail::masked_data (t2) ? detail::masked_data (t1)
657- : detail::masked_data (t2)
658- ),
659- true
660- );
661- }
662-
663- return return_type (value_type (0 ), false );
678+ using value_type = detail::masked_common_value_type_t <A1, A2>;
679+ return detail::masked_map<value_type>(
680+ [](const auto & lhs, const auto & rhs)
681+ {
682+ return lhs > rhs ? lhs : rhs;
683+ },
684+ t1,
685+ t2
686+ );
664687 }
665688 else
666689 {
@@ -680,7 +703,23 @@ namespace xt
680703 template <class A1 , class A2 , class A3 >
681704 constexpr auto operator ()(const A1& v, const A2& lo, const A3& hi) const
682705 {
683- return xtl::select (lo < hi, xtl::select (v < lo, lo, xtl::select (hi < v, hi, v)), hi);
706+ if constexpr (detail::has_masked_value_v<A1, A2, A3>)
707+ {
708+ using value_type = detail::masked_common_value_type_t <A1, A2, A3>;
709+ return detail::masked_map<value_type>(
710+ [](const auto & value, const auto & lower, const auto & upper)
711+ {
712+ return value < lower ? lower : (upper < value ? upper : value);
713+ },
714+ v,
715+ lo,
716+ hi
717+ );
718+ }
719+ else
720+ {
721+ return xtl::select (v < lo, lo, xtl::select (hi < v, hi, v));
722+ }
684723 }
685724
686725 template <class A1 , class A2 , class A3 >
@@ -692,16 +731,29 @@ namespace xt
692731
693732 struct deg2rad
694733 {
695- template <class A , std::enable_if_t <xtl::is_integral<A>::value, int > = 0 >
696- constexpr double operator ()(const A& a) const noexcept
697- {
698- return a * xt::numeric_constants<double >::PI / 180.0 ;
699- }
700-
701- template <class A , std::enable_if_t <std::is_floating_point<A>::value, int > = 0 >
734+ template <class A >
702735 constexpr auto operator ()(const A& a) const noexcept
703736 {
704- return a * xt::numeric_constants<A>::PI / A (180.0 );
737+ if constexpr (detail::has_masked_value_v<A>)
738+ {
739+ using data_type = detail::masked_data_type_t <A>;
740+ using result_type = std::conditional_t <xtl::is_integral<data_type>::value, double , data_type>;
741+ return detail::masked_map<result_type>(
742+ [](const auto & value)
743+ {
744+ return value * xt::numeric_constants<result_type>::PI / result_type (180.0 );
745+ },
746+ a
747+ );
748+ }
749+ else if constexpr (xtl::is_integral<A>::value)
750+ {
751+ return a * xt::numeric_constants<double >::PI / 180.0 ;
752+ }
753+ else
754+ {
755+ return a * xt::numeric_constants<A>::PI / A (180.0 );
756+ }
705757 }
706758
707759 template <class A , std::enable_if_t <xtl::is_integral<A>::value, int > = 0 >
@@ -719,16 +771,29 @@ namespace xt
719771
720772 struct rad2deg
721773 {
722- template <class A , std::enable_if_t <xtl::is_integral<A>::value, int > = 0 >
723- constexpr double operator ()(const A& a) const noexcept
724- {
725- return a * 180.0 / xt::numeric_constants<double >::PI;
726- }
727-
728- template <class A , std::enable_if_t <std::is_floating_point<A>::value, int > = 0 >
774+ template <class A >
729775 constexpr auto operator ()(const A& a) const noexcept
730776 {
731- return a * A (180.0 ) / xt::numeric_constants<A>::PI;
777+ if constexpr (detail::has_masked_value_v<A>)
778+ {
779+ using data_type = detail::masked_data_type_t <A>;
780+ using result_type = std::conditional_t <xtl::is_integral<data_type>::value, double , data_type>;
781+ return detail::masked_map<result_type>(
782+ [](const auto & value)
783+ {
784+ return value * result_type (180.0 ) / xt::numeric_constants<result_type>::PI;
785+ },
786+ a
787+ );
788+ }
789+ else if constexpr (xtl::is_integral<A>::value)
790+ {
791+ return a * 180.0 / xt::numeric_constants<double >::PI;
792+ }
793+ else
794+ {
795+ return a * A (180.0 ) / xt::numeric_constants<A>::PI;
796+ }
732797 }
733798
734799 template <class A , std::enable_if_t <xtl::is_integral<A>::value, int > = 0 >
@@ -932,7 +997,22 @@ namespace xt
932997 template <class T >
933998 constexpr auto operator ()(const T& x) const
934999 {
935- return sign_impl<T>::run (x);
1000+ if constexpr (detail::has_masked_value_v<T>)
1001+ {
1002+ using data_type = detail::masked_data_type_t <T>;
1003+ using result_type = std::decay_t <decltype (sign_impl<data_type>::run (detail::masked_data (x)))>;
1004+ return detail::masked_map<result_type>(
1005+ [](const auto & value)
1006+ {
1007+ return sign_impl<data_type>::run (value);
1008+ },
1009+ x
1010+ );
1011+ }
1012+ else
1013+ {
1014+ return sign_impl<T>::run (x);
1015+ }
9361016 }
9371017 };
9381018 }
0 commit comments