/*+ ARES/HADES/BORG Package -- ./libLSS/tools/fusewrapper.hpp Copyright (C) 2014-2020 Guilhem Lavaux Copyright (C) 2009-2020 Jens Jasche Additional contributions from: Guilhem Lavaux (2023) +*/ #ifndef __LIBLSS_FUSEWRAPPER_HPP #define __LIBLSS_FUSEWRAPPER_HPP #pragma once #include #include #include #include #include "libLSS/tools/fused_array.hpp" #include "libLSS/tools/fused_assign.hpp" #include "libLSS/tools/phoenix_vars.hpp" #include #include "libLSS/tools/fused_reduce.hpp" #include "libLSS/tools/fused_cond.hpp" #include #include #include #include #include "libLSS/tools/array_concepts.hpp" #include #include "libLSS/tools/uninitialized_type.hpp" namespace LibLSS { namespace FuseWrapper_detail { using LibLSS::array_concepts::is_array_like; using LibLSS::array_concepts::is_array_storage; using LibLSS::array_concepts::is_array_sub; using LibLSS::array_concepts::is_array_view; using LibLSS::array_concepts::is_callable; template struct Wrapper; template < typename Array, typename U = typename std::remove_reference::type> Wrapper fwrap_(Array &&a, std::true_type); template < typename Array, typename U = typename std::remove_reference::type> Wrapper fwrap_(Array &&a, std::false_type); template auto fwrap(UninitializedAllocation &a) { return fwrap_(a.get_array(), std::false_type()); } template < typename Array, typename = typename std::enable_if< is_array_like::type>::value, void>::type> auto fwrap(Array &&a) { return fwrap_( std::forward(a), std::is_rvalue_reference()); } template struct CopyType; template struct CopyType { typedef A type; typedef A const_type; }; template struct CopyType { typedef A &type; typedef A const &const_type; }; template struct constantFunctor { T value; constantFunctor(T v) : value(v) {} template T const &operator()(Args &&... a) const { return value; } }; template struct singleFunctor { typedef std::result_of Result; F f; singleFunctor() {} singleFunctor(F f_) : f(f_) {} template Result operator()(Args &&... a) const { return f(); } }; template struct Wrapper { typedef Array array_t; typedef typename CopyType::type WType; typedef typename CopyType::const_type WTypeConst; WType a; bool parallel; explicit Wrapper(Array &a_) : a(a_), parallel(true) {} explicit Wrapper(Array &&a_) : a(a_), parallel(true) {} template static inline auto fautowrap(UninitializedAllocation &a) { return Wrapper(a.get_array()); } Array &operator*() { return a; } Array const &operator*() const { return a; } Array *operator->() { return &a; } Array const *operator->() const { return &a; } Wrapper no_parallel() const { auto b = *this; b.parallel = false; return b; } // This auxiliary function creates a perfect // forwarding of the required encapsulation of the array. // If a copy is needed to ensure the object is long lived // enough, then WType is the full Array object. // Otherwise, it will be a reference on the original object. // Thus a receiving function will get either a lvalue-ref or an rvalue-ref // depending on the need. WType forward_wrap() { return a; } WTypeConst forward_wrap() const { return a; } template static inline typename Wrapper::WType const fautowrap(const Wrapper &other) { return other.a; } template static inline typename std::enable_if::value, U>::type const & fautowrap(Array2 const &other) { return other; } // Intel 17.2 C++ compiler crashes without those template struct wrapconst { typedef decltype(b_va_fused( constantFunctor(ValueType(0)))) Result; static inline Result wrap(ValueType value) { return (b_va_fused(constantFunctor(value))); } }; template struct wrapfunc { typedef decltype( b_va_fused(singleFunctor())) Result; static inline Result wrap(Operator op) { return (b_va_fused(singleFunctor(op))); } }; template static inline typename std::enable_if< (boost::is_arithmetic::value || array_concepts::is_complex_type::value) && is_array_like::value, wrapconst>::type::Result fautowrap(ValueType other) { return wrapconst::wrap(other); } template static inline typename boost::enable_if< is_callable, wrapfunc>::type:: Result fautowrap(F other) { return wrapfunc< typename Array::element, Array::dimensionality, F>::wrap(other); } typename Array::element sum() const { return LibLSS::reduce_sum(a, parallel); } typename Array::element min() const { return LibLSS::reduce_min(a, parallel); } typename Array::element max() const { return LibLSS::reduce_max(a, parallel); } template Wrapper const ©_to(ArrayTo &to) const { LibLSS::copy_array(to, a, to.parallel); return *this; } Wrapper &operator=(Wrapper &other) { return operator=((Wrapper const &)other); } template inline Wrapper &operator=(Wrap2 const &other) { static_assert( is_array_storage::value || is_array_view::value || is_array_sub::value, "The wrapped array is likely a pure expression. Impossible to " "assign."); LibLSS::copy_array(a, fautowrap(other), parallel); return *this; } }; } // namespace FuseWrapper_detail } // namespace LibLSS #include "libLSS/tools/fuse/operators.hpp" namespace LibLSS { using FuseWrapper_detail::fwrap; using FuseWrapper_detail::is_wrapper; template < size_t exponent, typename T, typename = typename boost::enable_if< boost::is_scalar::type>>::type> auto ipow(T &&t) { return CosmoTool::spower< exponent, typename boost::remove_reference::type>(t); } template struct _spower_helper { typedef decltype(CosmoTool::spower(T(0))) Return; inline Return operator()(T a) const { return CosmoTool::spower(a); } }; template auto ipow(LibLSS::FuseWrapper_detail::Wrapper wrap) { return fwrap( b_va_fused< typename _spower_helper::Return>( _spower_helper(), std::forward::WType>(wrap.a))); } template auto ones(ExtentType e) { return fwrap(b_fused_idx([](auto... x) { return T(1); }, e)); } template auto zero(ExtentType e) { return fwrap(b_fused_idx([](auto... x) { return T(0); }, e)); } template auto constant(T value, ExtentType e) { return fwrap( b_fused_idx([value](auto... x) { return T(value); }, e)); } template auto make_complex( LibLSS::FuseWrapper_detail::Wrapper wrap_re, LibLSS::FuseWrapper_detail::Wrapper wrap_im) { static_assert( std::is_same::value, "The two array have different base type"); typedef typename Array1::element element; return fwrap(b_va_fused>( [](element const &a, element const &b) { return std::complex(a, b); }, std::forward< typename LibLSS::FuseWrapper_detail::Wrapper::WType>( wrap_re.a), std::forward< typename LibLSS::FuseWrapper_detail::Wrapper::WType>( wrap_im.a))); } template < typename ArrayM, bool copyM, typename Array1, bool copy1, typename Array2, bool copy2> auto mask( LibLSS::FuseWrapper_detail::Wrapper wrap_mask, LibLSS::FuseWrapper_detail::Wrapper array1, LibLSS::FuseWrapper_detail::Wrapper array2) { return fwrap(b_cond_fused( wrap_mask.forward_wrap(), array1.forward_wrap(), array2.forward_wrap())); } } // namespace LibLSS #endif