// // SPDX-License-Identifier: BSD-3-Clause // Copyright Contributors to the OpenEXR Project. // // clang-format off #ifndef _PyImathAutovectorize_h_ #define _PyImathAutovectorize_h_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "PyImathFixedArray.h" #include "PyImathTask.h" #include "PyImathUtil.h" namespace PyImath { struct op_with_precomputation {}; namespace detail { using boost::is_base_of; using boost::is_same; using boost::is_const; using boost::remove_const; using boost::remove_reference; using boost::function_traits; using boost::mpl::at; using boost::mpl::at_c; using boost::mpl::push_front; using boost::mpl::vector; using boost::mpl::push_back; using boost::mpl::transform; using boost::mpl::fold; using boost::mpl::_; using boost::mpl::_1; using boost::mpl::_2; using boost::mpl::long_; using boost::mpl::false_; using boost::mpl::true_; using boost::mpl::not_; using boost::mpl::or_; using boost::mpl::and_; using boost::mpl::size; using boost::mpl::remove_if; using boost::mpl::if_; using boost::mpl::for_each; struct null_precomputation { static void precompute(size_t len) { return; } }; template struct op_precompute { static void apply(size_t len) { if_, T, null_precomputation>::type::precompute(len); } }; template struct possible_vectorizations { typedef typename fold< typename possible_vectorizations::type, vector<>, push_back >,push_back<_2,true_> > >::type type; }; template <> struct possible_vectorizations<0> { typedef vector > type; }; template struct disallow_vectorization { template struct apply { // Valid = !Vectorize || Vectorizable typedef typename transform >::type DontVectorize; typedef typename transform >::type Valid; typedef typename not_ > >::type type; }; }; template struct allowable_vectorizations { typedef typename possible_vectorizations::value>::type possible; typedef typename remove_if >::type type; }; template bool any_masked(const T &value) { return false; }; template bool any_masked(const PyImath::FixedArray &value) { return value.isMaskedReference(); }; template bool any_masked(const T1 &a, const T2 &b) { return any_masked(a) || any_masked(b); } template bool any_masked(const T1 &a, const T2 &b, const T3 &c) { return any_masked(a,b) || any_masked(c); } template bool any_masked(const T1 &a, const T2 &b, const T3 &c, const T4 &d) { return any_masked(a,b) || any_masked(c,d); } //----------------------------------------------------------------------------------------- // // measure_argument returns a pair indicating the integral length of the argument // (scalar arguments have implicit length 1), and a bool indicating whether the argument // is a vectorized argument. // template struct measure_argument { static inline std::pair apply(T arg) { return std::make_pair(1,false); } }; template struct measure_argument > { static inline std::pair apply(const PyImath::FixedArray &arg) { return std::make_pair(arg.len(),true); } }; // // match_lengths returns the compatible length given two argument lengths // static inline std::pair match_lengths(const std::pair &len1, const std::pair &len2) { // scalar arguemnts are always compatible with other arguments if (len1.second == false) return len2; if (len2.second == false) return len1; // now both arguments are vectorized, check for dimension match if (len1.first != len2.first) throw std::invalid_argument("Array dimensions passed into function do not match"); return len1; } // // measure_arguments finds the length that a return value from a given // set of arguments should have, throwing an exception if the lengths // are incompatible. If all arguments are scalar, length 1 is returned. // template size_t measure_arguments(const arg1_type &arg1) { std::pair len = measure_argument::apply(arg1); return len.first; } template size_t measure_arguments(const arg1_type &arg1, const arg2_type &arg2) { std::pair len = measure_argument::apply(arg1); len = match_lengths(len,measure_argument::apply(arg2)); return len.first; } template size_t measure_arguments(const arg1_type &arg1, const arg2_type &arg2, const arg3_type &arg3) { std::pair len = measure_argument::apply(arg1); len = match_lengths(len,measure_argument::apply(arg2)); len = match_lengths(len,measure_argument::apply(arg3)); return len.first; } template size_t measure_arguments(const arg1_type &arg1, const arg2_type &arg2, const arg3_type &arg3, const arg4_type &arg4) { std::pair len = measure_argument::apply(arg1); len = match_lengths(len,measure_argument::apply(arg2)); len = match_lengths(len,measure_argument::apply(arg3)); len = match_lengths(len,measure_argument::apply(arg4)); return len.first; } template size_t measure_arguments(const arg1_type &arg1, const arg2_type &arg2, const arg3_type &arg3, const arg4_type &arg4, const arg5_type &arg5) { std::pair len = measure_argument::apply(arg1); len = match_lengths(len,measure_argument::apply(arg2)); len = match_lengths(len,measure_argument::apply(arg3)); len = match_lengths(len,measure_argument::apply(arg4)); len = match_lengths(len,measure_argument::apply(arg5)); return len.first; } //----------------------------------------------------------------------------------------- template struct create_uninitalized_return_value { static T apply(size_t length) { return T(); } }; template struct create_uninitalized_return_value > { static PyImath::FixedArray apply(size_t length) { return PyImath::FixedArray(Py_ssize_t(length),PyImath::UNINITIALIZED); } }; template struct vectorized_result_type { typedef typename if_,T>::type type; }; template struct SimpleNonArrayWrapper { struct ReadOnlyDirectAccess { ReadOnlyDirectAccess (const T& arg) : _arg (arg) {} ReadOnlyDirectAccess (const ReadOnlyDirectAccess& other) : _arg (other._arg) {} const T& operator[] (size_t) const { return _arg; } private: const T& _arg; }; struct WritableDirectAccess : public ReadOnlyDirectAccess { WritableDirectAccess (T& arg) : ReadOnlyDirectAccess (arg), _arg (arg) {} WritableDirectAccess (const WritableDirectAccess& other) : ReadOnlyDirectAccess (other), _arg (other._arg) {} T& operator[] (size_t) { return _arg; } private: T& _arg; }; typedef ReadOnlyDirectAccess ReadOnlyMaskedAccess; typedef WritableDirectAccess WritableMaskedAccess; }; template struct access_type { typedef typename remove_reference::type prim_type; typedef typename remove_const::type base_type; typedef typename if_, const PyImath::FixedArray &, PyImath::FixedArray &>::type reference_type; typedef typename remove_reference::type class_type; typedef typename if_, typename class_type::ReadOnlyMaskedAccess, typename class_type::WritableMaskedAccess>::type masked; typedef typename if_, typename class_type::ReadOnlyDirectAccess, typename class_type::WritableDirectAccess>::type direct; }; template struct argument_access_type { typedef typename remove_const::type>::type base_type; typedef typename if_ &,T>::type type; typedef typename if_::type, SimpleNonArrayWrapper >::type _class_type; typedef typename _class_type::ReadOnlyMaskedAccess masked; typedef typename _class_type::ReadOnlyDirectAccess direct; }; template struct result_access_type { typedef typename remove_const::type>::type base_type; typedef typename if_,T>::type type; typedef typename if_ >::type _class_type; typedef typename _class_type::WritableMaskedAccess masked; typedef typename _class_type::WritableDirectAccess direct; }; template AccessType getArrayAccess (T& value) { return AccessType (value); } template AccessType getArrayAccess (const PyImath::FixedArray& array) { return AccessType (array); } template AccessType getArrayAccess (PyImath::FixedArray& array) { return AccessType (array); } // template struct VectorizedOperation1 : public Task { result_access_type retAccess; access_type access; VectorizedOperation1 (result_access_type r, access_type a1) : retAccess (r), access (a1) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { retAccess[i] = Op::apply (access[i]); } } }; template struct VectorizedOperation2 : public Task { result_access_type retAccess; access_type access; arg1_access_type argAccess; VectorizedOperation2(result_access_type r, access_type a1, arg1_access_type a2) : retAccess (r), access (a1), argAccess (a2) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { retAccess[i] = Op::apply (access[i], argAccess[i]); } } }; template struct VectorizedOperation3 : public Task { result_access_type retAccess; access_type access; arg1_access_type arg1Access; arg2_access_type arg2Access; VectorizedOperation3(result_access_type r, access_type a, arg1_access_type a1, arg2_access_type a2) : retAccess(r), access(a), arg1Access(a1), arg2Access(a2) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { retAccess[i] = Op::apply(access[i], arg1Access[i], arg2Access[i]); } } }; template struct VectorizedOperation4 : public Task { result_access_type retAccess; access_type access; arg1_access_type arg1Access; arg2_access_type arg2Access; arg3_access_type arg3Access; VectorizedOperation4(result_access_type r, access_type a, arg1_access_type a1, arg2_access_type a2, arg3_access_type a3) : retAccess(r), access(a), arg1Access(a1), arg2Access(a2), arg3Access(a3) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { retAccess[i] = Op::apply(access[i], arg1Access[i], arg2Access[i], arg3Access[i]); } } }; template struct VectorizedOperation5 : public Task { result_access_type retAccess; access_type access; arg1_access_type arg1Access; arg2_access_type arg2Access; arg3_access_type arg3Access; arg4_access_type arg4Access; VectorizedOperation5(result_access_type r, access_type a, arg1_access_type a1, arg2_access_type a2, arg3_access_type a3, arg4_access_type a4) : retAccess(r), access(a), arg1Access(a1), arg2Access(a2), arg3Access(a3), arg4Access(a4) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { retAccess[i] = Op::apply(access[i], arg1Access[i], arg2Access[i], arg3Access[i], arg4Access[i]); } } }; template struct VectorizedFunction1 { BOOST_STATIC_ASSERT((size::value == function_traits::arity)); typedef function_traits traits; typedef typename fold >::type any_vectorized; typedef typename result_access_type::type result_type; typedef typename result_access_type::direct result_access_type; // Result array is created here 'from scratch', so is always 'direct' access. typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; static result_type apply(arg1_type arg1) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(arg1); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type resultAccess = getArrayAccess (retval); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedOperation1 vop (resultAccess, argAccess); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedOperation1 vop (resultAccess, argAccess); dispatchTask(vop,len); } PY_IMATH_RETURN_PYTHON; return retval; } static std::string format_arguments(const boost::python::detail::keywords<1> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+") - "; } }; template struct VectorizedFunction2 { BOOST_STATIC_ASSERT((size::value == function_traits::arity)); typedef function_traits traits; typedef typename fold >::type any_vectorized; typedef typename result_access_type::type result_type; typedef typename result_access_type::direct result_access_type; // Result array is created here 'from scratch', so is always 'direct' access. typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; typedef typename argument_access_type >::type>::type arg2_type; typedef typename argument_access_type >::type>::direct arg2_direct_access_type; typedef typename argument_access_type >::type>::masked arg2_masked_access_type; static result_type apply(arg1_type arg1, arg2_type arg2) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(arg1,arg2); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type resultAccess = getArrayAccess (retval); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation2 vop (resultAccess, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation2 vop (resultAccess, arg1Access, arg2Access); dispatchTask(vop,len); } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation2 vop (resultAccess, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation2 vop (resultAccess, arg1Access, arg2Access); dispatchTask(vop,len); } } PY_IMATH_RETURN_PYTHON; return retval; } static std::string format_arguments(const boost::python::detail::keywords<2> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+","+args.elements[1].name+") - "; } }; template struct VectorizedFunction3 { BOOST_STATIC_ASSERT((size::value == function_traits::arity)); typedef function_traits traits; typedef typename fold >::type any_vectorized; typedef typename result_access_type::type result_type; typedef typename result_access_type::direct result_access_type; // Result array is created here 'from scratch', so is always 'direct' access. typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; typedef typename argument_access_type >::type>::type arg2_type; typedef typename argument_access_type >::type>::direct arg2_direct_access_type; typedef typename argument_access_type >::type>::masked arg2_masked_access_type; typedef typename argument_access_type >::type>::type arg3_type; typedef typename argument_access_type >::type>::direct arg3_direct_access_type; typedef typename argument_access_type >::type>::masked arg3_masked_access_type; static result_type apply(arg1_type arg1, arg2_type arg2, arg3_type arg3) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(arg1,arg2,arg3); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type resultAccess = getArrayAccess (retval); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); VectorizedOperation3 vop (resultAccess, arg1Access, arg2Access, arg3Access); dispatchTask(vop,len); } } } PY_IMATH_RETURN_PYTHON; return retval; } static std::string format_arguments(const boost::python::detail::keywords<3> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+","+args.elements[1].name+","+args.elements[2].name+") - "; } }; template struct VectorizedFunction4 { BOOST_STATIC_ASSERT((size::value == function_traits::arity)); typedef function_traits traits; typedef typename fold >::type any_vectorized; typedef typename result_access_type::type result_type; typedef typename result_access_type::direct result_access_type; // Result array is created here 'from scratch', so is always 'direct' access. typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; typedef typename argument_access_type >::type>::type arg2_type; typedef typename argument_access_type >::type>::direct arg2_direct_access_type; typedef typename argument_access_type >::type>::masked arg2_masked_access_type; typedef typename argument_access_type >::type>::type arg3_type; typedef typename argument_access_type >::type>::direct arg3_direct_access_type; typedef typename argument_access_type >::type>::masked arg3_masked_access_type; typedef typename argument_access_type >::type>::type arg4_type; typedef typename argument_access_type >::type>::direct arg4_direct_access_type; typedef typename argument_access_type >::type>::masked arg4_masked_access_type; static result_type apply(arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(arg1,arg2,arg3,arg4); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type resultAccess = getArrayAccess (retval); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); VectorizedOperation4 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access); dispatchTask(vop,len); } } } } PY_IMATH_RETURN_PYTHON; return retval; } static std::string format_arguments(const boost::python::detail::keywords<4> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+","+args.elements[1].name+","+args.elements[2].name+","+args.elements[3].name+") - "; } }; template struct VectorizedFunction5 { BOOST_STATIC_ASSERT((size::value == function_traits::arity)); typedef function_traits traits; typedef typename fold >::type any_vectorized; typedef typename result_access_type::type result_type; typedef typename result_access_type::direct result_access_type; // Result array is created here 'from scratch', so is always 'direct' access. typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; typedef typename argument_access_type >::type>::type arg2_type; typedef typename argument_access_type >::type>::direct arg2_direct_access_type; typedef typename argument_access_type >::type>::masked arg2_masked_access_type; typedef typename argument_access_type >::type>::type arg3_type; typedef typename argument_access_type >::type>::direct arg3_direct_access_type; typedef typename argument_access_type >::type>::masked arg3_masked_access_type; typedef typename argument_access_type >::type>::type arg4_type; typedef typename argument_access_type >::type>::direct arg4_direct_access_type; typedef typename argument_access_type >::type>::masked arg4_masked_access_type; typedef typename argument_access_type >::type>::type arg5_type; typedef typename argument_access_type >::type>::direct arg5_direct_access_type; typedef typename argument_access_type >::type>::masked arg5_masked_access_type; static result_type apply(arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, arg5_type arg5) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(arg1,arg2,arg3,arg4,arg5); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type resultAccess = getArrayAccess (retval); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); if (any_masked(arg3)) { arg3_masked_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } else { arg3_direct_access_type arg3Access = getArrayAccess (arg3); if (any_masked(arg4)) { arg4_masked_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } else { arg4_direct_access_type arg4Access = getArrayAccess (arg4); if (any_masked(arg5)) { arg5_masked_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } else { arg5_direct_access_type arg5Access = getArrayAccess (arg5); VectorizedOperation5 vop (resultAccess, arg1Access, arg2Access, arg3Access, arg4Access, arg5Access); dispatchTask(vop,len); } } } } } PY_IMATH_RETURN_PYTHON; return retval; } static std::string format_arguments(const boost::python::detail::keywords<5> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+","+args.elements[1].name+","+args.elements[2].name+","+args.elements[3].name+","+args.elements[4].name+") - "; } }; template struct function_binding { std::string _name, _doc; const Keywords &_args; function_binding(const std::string &name, const std::string &doc,const Keywords &args) : _name(name), _doc(doc), _args(args) {} template void operator()(Vectorize) const { typedef typename at, VectorizedFunction2, VectorizedFunction3, VectorizedFunction4, VectorizedFunction5 >, long_::arity> >::type vectorized_function_type; std::string doc = _name + vectorized_function_type::format_arguments(_args) + _doc; boost::python::def(_name.c_str(),&vectorized_function_type::apply,doc.c_str(),_args); } }; template function_binding build_function_binding(Func *func,const std::string &name,const std::string &doc,const Keywords &args) { return function_binding(name,doc,args); } template struct generate_bindings_struct { //BOOST_STATIC_ASSERT(size::value == function_traits::arity); static void apply(const std::string &name,const std::string &doc,const Keywords &args) { for_each::type>(build_function_binding(Op::apply,name,doc,args)); } }; template struct VectorizedVoidOperation0 : public Task { access_type access; VectorizedVoidOperation0 (access_type a) : access(a) {} void execute (size_t start, size_t end) { for (size_t i = start; i < end; ++i) { Op::apply (access[i]); } } }; template struct VectorizedVoidOperation1 : public Task { access_type access; arg1_access_type arg1; VectorizedVoidOperation1(access_type a, arg1_access_type a1) : access(a), arg1(a1) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { Op::apply (access[i], arg1[i]); } } }; template struct VectorizedMaskedVoidOperation1 : public Task { access_type access; arg1_access_type arg1; array_type array; VectorizedMaskedVoidOperation1(access_type a, arg1_access_type a1, array_type arr) : access(a), arg1(a1), array(arr) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { const size_t ri = array.raw_ptr_index(i); Op::apply (access[i], arg1[ri]); } } }; template struct VectorizedVoidOperation2 : public Task { access_type access; arg1_access_type arg1; arg2_access_type arg2; VectorizedVoidOperation2(access_type a, arg1_access_type a1, arg2_access_type a2) : access(a), arg1(a1), arg2(a2) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { Op::apply (access[i], arg1[i], arg2[i]); } } }; template struct VectorizedVoidMemberFunction0 { BOOST_STATIC_ASSERT((size::value+1 == function_traits::arity)); typedef function_traits traits; typedef typename access_type::reference_type reference_type; typedef typename access_type::direct direct_access_type; typedef typename access_type::masked masked_access_type; static reference_type apply(reference_type array) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(array); op_precompute::apply(len); if (any_masked(array)) { masked_access_type access (array); VectorizedVoidOperation0 vop (access); dispatchTask(vop,len); } else { direct_access_type access (array); VectorizedVoidOperation0 vop (access); dispatchTask(vop,len); } PY_IMATH_RETURN_PYTHON; return array; } }; template struct VectorizedVoidMemberFunction1 { BOOST_STATIC_ASSERT((size::value+1 == function_traits::arity)); typedef function_traits traits; typedef typename access_type::reference_type reference_type; typedef typename access_type::direct direct_access_type; typedef typename access_type::masked masked_access_type; typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; static reference_type apply(reference_type array, arg1_type arg1) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(array,arg1); op_precompute::apply(len); if (any_masked(array)) { masked_access_type arrayAccess (array); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } } else { direct_access_type arrayAccess (array); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } } PY_IMATH_RETURN_PYTHON; return array; } static std::string format_arguments(const boost::python::detail::keywords<1> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+") - "; } }; // // special class to handle single argument void memberfunctions, such as those // used for the inplace operators like +=, -=, etc. In this case we allow additional // compatibilty between a masked class and an unmasked right hand side, using the // mask to select results. // template struct VectorizedVoidMaskableMemberFunction1 { BOOST_STATIC_ASSERT((2 == function_traits::arity)); typedef function_traits traits; typedef typename access_type::reference_type reference_type; typedef typename access_type::direct direct_access_type; typedef typename access_type::masked masked_access_type; typedef typename argument_access_type::type arg1_type; typedef typename argument_access_type::direct arg1_direct_access_type; typedef typename argument_access_type::masked arg1_masked_access_type; static reference_type apply(reference_type array, arg1_type arg1) { PY_IMATH_LEAVE_PYTHON; size_t len = array.match_dimension(arg1, false); op_precompute::apply(len); if (array.isMaskedReference() && (size_t) arg1.len() == array.unmaskedLength()) { // class is masked, and the unmasked length matches the right hand side masked_access_type arrayAccess (array); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedMaskedVoidOperation1 vop (arrayAccess, argAccess, array); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedMaskedVoidOperation1 vop (arrayAccess, argAccess, array); dispatchTask(vop,len); } } else { // the two arrays match length (masked or otherwise), use the standard path. if (any_masked(array)) { masked_access_type arrayAccess (array); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } } else { direct_access_type arrayAccess (array); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedVoidOperation1 vop (arrayAccess, argAccess); dispatchTask(vop,len); } } } PY_IMATH_RETURN_PYTHON; return array; } static std::string format_arguments(const boost::python::detail::keywords<1> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+") - "; } }; template struct VectorizedVoidMemberFunction2 { BOOST_STATIC_ASSERT((size::value+1 == function_traits::arity)); typedef function_traits traits; typedef typename access_type::reference_type reference_type; typedef typename access_type::direct direct_access_type; typedef typename access_type::masked masked_access_type; typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; typedef typename argument_access_type >::type>::type arg2_type; typedef typename argument_access_type >::type>::direct arg2_direct_access_type; typedef typename argument_access_type >::type>::masked arg2_masked_access_type; static reference_type apply(reference_type array, arg1_type arg1, arg2_type arg2) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(array,arg1,arg2); op_precompute::apply(len); if (any_masked(array)) { masked_access_type arrayAccess (array); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } } } else { direct_access_type arrayAccess (array); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedVoidOperation2 vop (arrayAccess, arg1Access, arg2Access); dispatchTask(vop,len); } } } PY_IMATH_RETURN_PYTHON; return array; } static std::string format_arguments(const boost::python::detail::keywords<2> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+","+args.elements[1].name+") - "; } }; template struct VectorizedMemberFunction0 { BOOST_STATIC_ASSERT((size::value+1 == function_traits::arity)); typedef function_traits traits; typedef typename vectorized_result_type::type result_type; typedef typename access_type::reference_type reference_type; typedef typename access_type::direct direct_access_type; typedef typename access_type::masked masked_access_type; // The return value can't be const or masked. Verify that condition. BOOST_STATIC_ASSERT( !is_const::value ); typedef typename result_type::WritableDirectAccess result_access_type; static result_type apply(reference_type array) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(array); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type returnAccess (retval); if (any_masked(array)) { masked_access_type access (array); VectorizedOperation1 vop(returnAccess,access); dispatchTask(vop,len); } else { direct_access_type access (array); VectorizedOperation1 vop(returnAccess,access); dispatchTask(vop,len); } PY_IMATH_RETURN_PYTHON; return retval; } }; template struct VectorizedMemberFunction1 { BOOST_STATIC_ASSERT((size::value+1 == function_traits::arity)); typedef function_traits traits; typedef typename vectorized_result_type::type result_type; typedef typename access_type::reference_type reference_type; typedef typename access_type::direct direct_access_type; typedef typename access_type::masked masked_access_type; typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; // The return value can't be const or masked. Verify that condition. BOOST_STATIC_ASSERT( !is_const::value ); typedef typename result_type::WritableDirectAccess result_access_type; static result_type apply(reference_type array, arg1_type arg1) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(array,arg1); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type returnAccess (retval); if (any_masked(array)) { masked_access_type access (array); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedOperation2 vop (returnAccess, access, argAccess); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedOperation2 vop (returnAccess, access, argAccess); dispatchTask(vop,len); } } else { direct_access_type access (array); if (any_masked(arg1)) { arg1_masked_access_type argAccess = getArrayAccess (arg1); VectorizedOperation2 vop (returnAccess, access, argAccess); dispatchTask(vop,len); } else { arg1_direct_access_type argAccess = getArrayAccess (arg1); VectorizedOperation2 vop (returnAccess, access, argAccess); dispatchTask(vop,len); } } PY_IMATH_RETURN_PYTHON; return retval; } static std::string format_arguments(const boost::python::detail::keywords<1> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+") - "; } }; template struct VectorizedMemberFunction2 { BOOST_STATIC_ASSERT((size::value+1 == function_traits::arity)); typedef function_traits traits; typedef typename vectorized_result_type::type result_type; typedef typename access_type::reference_type reference_type; typedef typename access_type::direct direct_access_type; typedef typename access_type::masked masked_access_type; typedef typename argument_access_type >::type>::type arg1_type; typedef typename argument_access_type >::type>::direct arg1_direct_access_type; typedef typename argument_access_type >::type>::masked arg1_masked_access_type; typedef typename argument_access_type >::type>::type arg2_type; typedef typename argument_access_type >::type>::direct arg2_direct_access_type; typedef typename argument_access_type >::type>::masked arg2_masked_access_type; // The return value can't be const or masked. Verify that condition. BOOST_STATIC_ASSERT( !is_const::value ); typedef typename result_type::WritableDirectAccess result_access_type; static result_type apply(reference_type array, arg1_type arg1, arg2_type arg2) { PY_IMATH_LEAVE_PYTHON; size_t len = measure_arguments(array,arg1,arg2); op_precompute::apply(len); result_type retval = create_uninitalized_return_value::apply(len); result_access_type returnAccess (retval); if (any_masked(array)) { masked_access_type access (array); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } } } else { direct_access_type access (array); if (any_masked(arg1)) { arg1_masked_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } } else { arg1_direct_access_type arg1Access = getArrayAccess (arg1); if (any_masked(arg2)) { arg2_masked_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } else { arg2_direct_access_type arg2Access = getArrayAccess (arg2); VectorizedOperation3 vop (returnAccess, access, arg1Access, arg2Access); dispatchTask(vop,len); } } } PY_IMATH_RETURN_PYTHON; return retval; } static std::string format_arguments(const boost::python::detail::keywords<2> &args) { // TODO: add types here return std::string("(")+args.elements[0].name+","+args.elements[1].name+") - "; } }; template struct member_function_binding { Cls &_cls; std::string _name, _doc; const Keywords &_args; member_function_binding(Cls &cls,const std::string &name, const std::string &doc,const Keywords &args) : _cls(cls), _name(name), _doc(doc), _args(args) {} template void operator()(Vectorize) const { typedef typename if_::result_type>, typename if_ >, VectorizedVoidMaskableMemberFunction1, VectorizedVoidMemberFunction1 >::type, VectorizedMemberFunction1 >::type member_func1_type; typedef typename if_::result_type>, VectorizedVoidMemberFunction2, VectorizedMemberFunction2 >::type member_func2_type; typedef typename if_::result_type>, boost::python::return_internal_reference<>, // the void vectorizations return a reference to self boost::python::default_call_policies>::type call_policies; typedef typename at, long_::arity> >::type vectorized_function_type; std::string doc = _name + vectorized_function_type::format_arguments(_args) + _doc; _cls.def(_name.c_str(),&vectorized_function_type::apply,doc.c_str(),_args,call_policies()); } }; template member_function_binding build_member_function_binding(Cls &cls,Func *func,const std::string &name,const std::string &doc,const Keywords &args) { return member_function_binding(cls,name,doc,args); } template struct generate_member_bindings_struct { //BOOST_STATIC_ASSERT(size::value+1 == function_traits::arity); static void apply(Cls &cls,const std::string &name,const std::string &doc,const Keywords &args) { for_each::type>(build_member_function_binding(cls,Op::apply,name,doc,args)); } }; template void generate_single_member_binding(Cls &cls,Func *func,const std::string &name,const std::string &doc) { typedef typename if_::result_type>, VectorizedVoidMemberFunction0,Func>, VectorizedMemberFunction0,Func> >::type vectorized_function_type; typedef typename if_::result_type>, boost::python::return_internal_reference<>, // the void vectorizations return a reference to self boost::python::default_call_policies>::type call_policies; cls.def(name.c_str(),&vectorized_function_type::apply,doc.c_str(),call_policies()); } } // namespace detail // TODO: update for arg("name")=default_value syntax template void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<1> &args) { using namespace detail; generate_bindings_struct,boost::python::detail::keywords<1> >::apply(name,doc,args); } template void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<2> &args) { using namespace detail; generate_bindings_struct,boost::python::detail::keywords<2> >::apply(name,doc,args); } template void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<3> &args) { using namespace detail; generate_bindings_struct,boost::python::detail::keywords<3> >::apply(name,doc,args); } template void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<4> &args) { using namespace detail; generate_bindings_struct,boost::python::detail::keywords<4> >::apply(name,doc,args); } template void generate_bindings(const std::string &name,const std::string &doc,const boost::python::detail::keywords<5> &args) { using namespace detail; generate_bindings_struct,boost::python::detail::keywords<5> >::apply(name,doc,args); } template void generate_member_bindings(Cls &cls,const std::string &name,const std::string &doc) { using namespace detail; generate_single_member_binding(cls,&Op::apply,name,doc); } template void generate_member_bindings(Cls &cls,const std::string &name,const std::string &doc, const boost::python::detail::keywords<1> &args) { using boost::mpl::vector; detail::generate_member_bindings_struct, boost::python::detail::keywords<1> >::apply(cls,name,doc,args); } template void generate_member_bindings(Cls &cls,const std::string &name,const std::string &doc, const boost::python::detail::keywords<2> &args) { using boost::mpl::vector; detail::generate_member_bindings_struct, boost::python::detail::keywords<2> >::apply(cls,name,doc,args); } } // namespace PyImath #endif // _PyImathAutovectorize_h_