diff --git a/dune/solvers/common/algorithm.hh b/dune/solvers/common/algorithm.hh index e99cc75f52b87d7f20c15f27de0f2238bc1d89c8..fc47a3b5f24780c20da07f7c9b047733a57f52a7 100644 --- a/dune/solvers/common/algorithm.hh +++ b/dune/solvers/common/algorithm.hh @@ -52,6 +52,31 @@ template<class T> struct IsIntegralConstant : public IsIntegralConstantHelper<std::decay_t<T>> {}; + + +// Compute t1==t2 either statically or dynamically +template<class T1, class T2> +constexpr auto hybridEqual(const T1& t1, const T2& t2, PriorityTag<1>) -> decltype(T1::value, T2::value, std::integral_constant<bool,T1::value == T2::value>()) +{ return {}; } + +template<class T1, class T2> +constexpr auto hybridEqual(const T1& t1, const T2& t2, PriorityTag<0>) +{ + return t1==t2; +} + +template<class IfFunc, class ElseFunc> +void staticIf(IfFunc&& ifFunc, ElseFunc&& elseFunc, std::false_type) +{ + elseFunc([](auto&& x) { return std::forward<decltype(x)>(x);}); +} + +template<class IfFunc, class ElseFunc> +void staticIf(IfFunc&& ifFunc, ElseFunc&& elseFunc, std::true_type) +{ + ifFunc([](auto&& x) { return std::forward<decltype(x)>(x);}); +} + } //end namespace Imp @@ -271,6 +296,90 @@ void sparseRangeFor(Range&& range, F&& f) +/** + * \brief Hybrid equality comparison + * + * If both types have a static member value, the result of comparing + * these is returned as std::integral_constant<bool, *>. Otherwise + * the result of a runtime comparison of t1 and t2 is directly returned. + */ +template<class T1, class T2> +constexpr auto hybridEqual(const T1& t1, const T2& t2) +{ + return Imp::hybridEqual(t1, t2, PriorityTag<1>()); +} + + +/** + * \brief Static if emulation + * + * This will call either ifFunc or elseFunc depending + * on the condition. In any case a single argument + * will be passed to the called function. This will always + * be the indentity function. Passing an expression through + * this function will lead to lazy evaluation. This way both + * 'branches' can contain expressions that are only valid + * within this branch. + */ +template<bool condition, class IfFunc, class ElseFunc> +void staticIf(IfFunc&& ifFunc, ElseFunc&& elseFunc) +{ + Imp::staticIf(std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc), std::integral_constant<bool, condition>()); +} + + + +namespace Imp { + +template<bool condition, class IfFunc, class ElseFunc> +void hybridIf(const std::integral_constant<bool, condition>&, IfFunc&& ifFunc, ElseFunc&& elseFunc) +{ + staticIf<condition>(std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc)); +} + +template<class IfFunc, class ElseFunc> +void hybridIf(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc) +{ + if (condition) + ifFunc([](auto&& x) { return std::forward<decltype(x)>(x);}); + else + elseFunc([](auto&& x) { return std::forward<decltype(x)>(x);}); +} + +} // namespace Imp + + + +/** + * \brief Hybrid if + * + * This will call either ifFunc or elseFunc depending + * on the condition. In any case a single argument + * will be passed to the called function. This will always + * be the indentity function. Passing an expression through + * this function will lead to lazy evaluation. This way both + * 'branches' can contain expressions that are only valid + * within this branch if the condition is a std::integral_constant<bool,*>. + */ +template<class Condition, class IfFunc, class ElseFunc> +void hybridIf(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc) +{ + Imp::hybridIf(condition, std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc)); +} + + + +/** + * \brief Hybrid if + * + * This provides a hybridIf with empty else clause. + */ +template<class Condition, class IfFunc> +void hybridIf(const Condition& condition, IfFunc&& ifFunc) +{ + hybridIf(condition, std::forward<IfFunc>(ifFunc), [](auto&& i) {}); +} + } // namespace Solvers } // namespace Dune