1 // Copyright Jim Bosch 2010-2012.
2 // Copyright Stefan Seefeld 2016.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #ifndef boost_python_numpy_invoke_matching_hpp_
8 #define boost_python_numpy_invoke_matching_hpp_
9 
10 /**
11  *  @brief Template invocation based on dtype matching.
12  */
13 
14 #include <boost/python/numpy/dtype.hpp>
15 #include <boost/python/numpy/ndarray.hpp>
16 #include <boost/mpl/integral_c.hpp>
17 
18 namespace boost { namespace python { namespace numpy {
19 namespace detail
20 {
21 
22 struct BOOST_NUMPY_DECL add_pointer_meta
23 {
24   template <typename T>
25   struct apply
26   {
27     typedef typename boost::add_pointer<T>::type type;
28   };
29 
30 };
31 
32 struct BOOST_NUMPY_DECL dtype_template_match_found {};
33 struct BOOST_NUMPY_DECL nd_template_match_found {};
34 
35 template <typename Function>
36 struct dtype_template_invoker
37 {
38 
39   template <typename T>
operator ()boost::python::numpy::detail::dtype_template_invoker40   void operator()(T *) const
41   {
42     if (dtype::get_builtin<T>() == m_dtype)
43     {
44       m_func.Function::template apply<T>();
45       throw dtype_template_match_found();
46     }
47   }
48 
dtype_template_invokerboost::python::numpy::detail::dtype_template_invoker49   dtype_template_invoker(dtype const & dtype_, Function func)
50     : m_dtype(dtype_), m_func(func) {}
51 
52 private:
53   dtype const & m_dtype;
54   Function m_func;
55 };
56 
57 template <typename Function>
58 struct dtype_template_invoker< boost::reference_wrapper<Function> >
59 {
60 
61   template <typename T>
operator ()boost::python::numpy::detail::dtype_template_invoker62   void operator()(T *) const
63   {
64     if (dtype::get_builtin<T>() == m_dtype)
65     {
66       m_func.Function::template apply<T>();
67       throw dtype_template_match_found();
68     }
69   }
70 
dtype_template_invokerboost::python::numpy::detail::dtype_template_invoker71   dtype_template_invoker(dtype const & dtype_, Function & func)
72     : m_dtype(dtype_), m_func(func) {}
73 
74 private:
75   dtype const & m_dtype;
76   Function & m_func;
77 };
78 
79 template <typename Function>
80 struct nd_template_invoker
81 {
82   template <int N>
operator ()boost::python::numpy::detail::nd_template_invoker83   void operator()(boost::mpl::integral_c<int,N> *) const
84   {
85     if (m_nd == N)
86     {
87       m_func.Function::template apply<N>();
88       throw nd_template_match_found();
89     }
90   }
91 
nd_template_invokerboost::python::numpy::detail::nd_template_invoker92   nd_template_invoker(int nd, Function func) : m_nd(nd), m_func(func) {}
93 
94 private:
95   int m_nd;
96   Function m_func;
97 };
98 
99 template <typename Function>
100 struct nd_template_invoker< boost::reference_wrapper<Function> >
101 {
102   template <int N>
operator ()boost::python::numpy::detail::nd_template_invoker103   void operator()(boost::mpl::integral_c<int,N> *) const
104   {
105     if (m_nd == N)
106     {
107       m_func.Function::template apply<N>();
108       throw nd_template_match_found();
109     }
110   }
111 
nd_template_invokerboost::python::numpy::detail::nd_template_invoker112   nd_template_invoker(int nd, Function & func) : m_nd(nd), m_func(func) {}
113 
114 private:
115   int m_nd;
116   Function & m_func;
117 };
118 
119 } // namespace boost::python::numpy::detail
120 
121 template <typename Sequence, typename Function>
invoke_matching_nd(int nd,Function f)122 void invoke_matching_nd(int nd, Function f)
123 {
124   detail::nd_template_invoker<Function> invoker(nd, f);
125   try { boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);}
126   catch (detail::nd_template_match_found &) { return;}
127   PyErr_SetString(PyExc_TypeError, "number of dimensions not found in template list.");
128   python::throw_error_already_set();
129 }
130 
131 template <typename Sequence, typename Function>
invoke_matching_dtype(dtype const & dtype_,Function f)132 void invoke_matching_dtype(dtype const & dtype_, Function f)
133 {
134   detail::dtype_template_invoker<Function> invoker(dtype_, f);
135   try { boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);}
136   catch (detail::dtype_template_match_found &) { return;}
137   PyErr_SetString(PyExc_TypeError, "dtype not found in template list.");
138   python::throw_error_already_set();
139 }
140 
141 namespace detail
142 {
143 
144 template <typename T, typename Function>
145 struct array_template_invoker_wrapper_2
146 {
147   template <int N>
applyboost::python::numpy::detail::array_template_invoker_wrapper_2148   void apply() const { m_func.Function::template apply<T,N>();}
array_template_invoker_wrapper_2boost::python::numpy::detail::array_template_invoker_wrapper_2149   array_template_invoker_wrapper_2(Function & func) : m_func(func) {}
150 
151 private:
152   Function & m_func;
153 };
154 
155 template <typename DimSequence, typename Function>
156 struct array_template_invoker_wrapper_1
157 {
158   template <typename T>
applyboost::python::numpy::detail::array_template_invoker_wrapper_1159   void apply() const { invoke_matching_nd<DimSequence>(m_nd, array_template_invoker_wrapper_2<T,Function>(m_func));}
array_template_invoker_wrapper_1boost::python::numpy::detail::array_template_invoker_wrapper_1160   array_template_invoker_wrapper_1(int nd, Function & func) : m_nd(nd), m_func(func) {}
161 
162 private:
163   int m_nd;
164   Function & m_func;
165 };
166 
167 template <typename DimSequence, typename Function>
168 struct array_template_invoker_wrapper_1< DimSequence, boost::reference_wrapper<Function> >
169   : public array_template_invoker_wrapper_1< DimSequence, Function >
170 {
array_template_invoker_wrapper_1boost::python::numpy::detail::array_template_invoker_wrapper_1171   array_template_invoker_wrapper_1(int nd, Function & func)
172     : array_template_invoker_wrapper_1< DimSequence, Function >(nd, func) {}
173 };
174 
175 } // namespace boost::python::numpy::detail
176 
177 template <typename TypeSequence, typename DimSequence, typename Function>
invoke_matching_array(ndarray const & array_,Function f)178 void invoke_matching_array(ndarray const & array_, Function f)
179 {
180   detail::array_template_invoker_wrapper_1<DimSequence,Function> wrapper(array_.get_nd(), f);
181   invoke_matching_dtype<TypeSequence>(array_.get_dtype(), wrapper);
182 }
183 
184 }}} // namespace boost::python::numpy
185 
186 #endif
187