diff --git a/dune/solvers/common/algorithm.hh b/dune/solvers/common/algorithm.hh index c5155fa776ef6caee49e3068543cadf35a1ffe5d..26137563ea3bad05581b43586e08a73b7433341b 100644 --- a/dune/solvers/common/algorithm.hh +++ b/dune/solvers/common/algorithm.hh @@ -9,6 +9,7 @@ namespace Dune { namespace Solvers { +// Everything in the next namespace block is just used to implement integralRangeFor namespace Imp { template<class ST, ST begin, ST end> @@ -110,6 +111,123 @@ void integralRangeFor(Begin&& begin, End&& end, F&& f, Args&&... args) } + +// Everything in the next namespace block is just used to implement StaticSize, HasStaticSize, hybridSize +namespace Imp { + +// As a last resort try if there's a static constexpr size() +template<class T> +constexpr auto staticSize(const T*, const PriorityTag<0>&) + -> decltype(std::integral_constant<std::size_t,T::size()>()) +{ + return {}; +} + +// Try if class has constexpr default constructor and size method +template<class T> +constexpr auto staticSize(const T*, const PriorityTag<1>&) + -> decltype(std::integral_constant<std::size_t,T().size()>()) +{ + return {}; +} + +// Try if tuple_size is implemented for class +template<class T> +constexpr auto staticSize(const T*, const PriorityTag<2>&) + -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>()) +{ + return {}; +} + +template<class T> +constexpr std::false_type hasStaticSize(const T* t, const PriorityTag<0>& p) +{ + return {}; +} + +template<class T> +constexpr auto hasStaticSize(const T* t, const PriorityTag<1>& p) + -> decltype(staticSize(t ,PriorityTag<42>()), std::true_type()) +{ + return {}; +} + +} + + + +/** + * \brief Check if type is a statically sized container + * + * \ingroup Utility + * + * Derives from std::true_type or std::false_type + */ +template<class T> +struct HasStaticSize : + public decltype(Imp::hasStaticSize((typename std::decay<T>::type*)(nullptr), PriorityTag<42>())) +{}; + + + +/** + * \brief Obtain size of statically sized container + * + * \ingroup Utility + * + * Derives from std::integral_constant<std::size_t, size> + */ +template<class T> +struct StaticSize : + public decltype(Imp::staticSize((typename std::decay<T>::type*)(nullptr), PriorityTag<42>())) +{}; + + + +/** + * \brief Hybrid size query + * + * \tparam T Type of container whose size is queried + * + * \param t Container whose size is queried + * + * This function is hybrid in the sense that it returns a statically + * encoded size, i.e., an integral_constant if possible and the + * dynamic result of the t.size() method otherwise. + * + * This is the static-size overload which returns the size i + * as std::integral_constant<std::size_t, i>. + */ +template<class T, + std::enable_if_t<HasStaticSize<T>::value, int> = 0> +auto hybridSize(const T& t) +{ + return Imp::staticSize((T*)(nullptr), PriorityTag<42>()); +} + +/** + * \brief Hybrid size query + * + * \tparam T Type of container whose size is queried + * + * \param t Container whose size is queried + * + * This function is hybrid in the sense that it returns a statically + * encoded size, i.e., an integral_constant if possible and the + * dynamic result of the *.size() method otherwise. + * + * This is the dynamic-size overload which returns the result + * of t.size(). + */ +template<class T, + std::enable_if_t<not HasStaticSize<T>::value, int> = 0> +auto hybridSize(const T& t) +{ + return t.size(); +} + + + } // namespace Solvers } // namespace Dune