1515namespace matplotlibcpp {
1616
1717 namespace detail {
18- struct _pyplot_global {
18+ struct _interpreter {
1919 PyObject *s_python_function_show;
2020 PyObject *s_python_function_figure;
2121 PyObject *s_python_function_plot;
@@ -24,13 +24,20 @@ namespace matplotlibcpp {
2424 PyObject *s_python_function_ylim;
2525 PyObject *s_python_empty_tuple;
2626
27- static _pyplot_global& get () {
28- static _pyplot_global ctx;
27+ /* For now, _interpreter is implemented as a singleton since its currently not possible to have
28+ multiple independent embedded python interpreters without patching the python source code
29+ or starting a seperate process for each.
30+
31+ http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
32+ */
33+
34+ static _interpreter& get () {
35+ static _interpreter ctx;
2936 return ctx;
3037 }
3138
3239 private:
33- _pyplot_global () {
40+ _interpreter () {
3441 char name[] = " plotting" ; // silence compiler warning abount const strings
3542 Py_SetProgramName (name); // optional but recommended
3643 Py_Initialize ();
@@ -68,7 +75,7 @@ namespace matplotlibcpp {
6875 s_python_empty_tuple = PyTuple_New (0 );
6976 }
7077
71- ~_pyplot_global () {
78+ ~_interpreter () {
7279 Py_Finalize ();
7380 }
7481 };
@@ -105,7 +112,7 @@ namespace matplotlibcpp {
105112 PyDict_SetItemString (kwargs, it->first .c_str (), PyString_FromString (it->second .c_str ()));
106113 }
107114
108- PyObject* res = PyObject_Call (detail::_pyplot_global ::get ().s_python_function_plot , args, kwargs);
115+ PyObject* res = PyObject_Call (detail::_interpreter ::get ().s_python_function_plot , args, kwargs);
109116
110117 Py_DECREF (args);
111118 Py_DECREF (kwargs);
@@ -136,7 +143,7 @@ namespace matplotlibcpp {
136143 PyTuple_SetItem (plot_args, 1 , ylist);
137144 PyTuple_SetItem (plot_args, 2 , pystring);
138145
139- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_plot , plot_args);
146+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_plot , plot_args);
140147
141148 Py_DECREF (xlist);
142149 Py_DECREF (ylist);
@@ -166,7 +173,7 @@ namespace matplotlibcpp {
166173 PyTuple_SetItem (plot_args, 1 , ylist);
167174 PyTuple_SetItem (plot_args, 2 , pystring);
168175
169- PyObject* res = PyObject_Call (detail::_pyplot_global ::get ().s_python_function_plot , plot_args, kwargs);
176+ PyObject* res = PyObject_Call (detail::_interpreter ::get ().s_python_function_plot , plot_args, kwargs);
170177
171178 Py_DECREF (kwargs);
172179 Py_DECREF (xlist);
@@ -205,119 +212,8 @@ namespace matplotlibcpp {
205212 return named_plot<double >(name,x,y,format);
206213 }
207214
208- #if __cplusplus > 199711L
209-
210- template <typename T>
211- using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
212-
213- template <bool obj, typename T>
214- struct is_callable_impl ;
215-
216- template <typename T>
217- struct is_callable_impl <false , T>
218- {
219- typedef is_function<T> type;
220- }; // a non-object is callable iff it is a function
221-
222- template <typename T>
223- struct is_callable_impl <true , T>
224- {
225- struct Fallback { void operator ()(); };
226- struct Derived : T, Fallback { };
227-
228- template <typename U, U> struct Check ;
229-
230- template <typename U>
231- static std::true_type test ( ... ); // use a variadic function to make use (1) it accepts everything and (2) its always the worst match
232-
233- template <typename U>
234- static std::false_type test ( Check<void (Fallback::*)(), &U::operator()>* );
235-
236- public:
237- typedef decltype (test<Derived>(nullptr )) type;
238- typedef decltype (&Fallback::operator ()) dtype;
239- static constexpr bool value = type::value;
240- }; // an object is callable iff it defines operator()
241-
242- template <typename T>
243- struct is_callable
244- {
245- // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
246- typedef typename is_callable_impl<std::is_class<T>::value, T>::type type; // todo: restore remove_reference
247- };
248-
249- template <typename IsYDataCallable>
250- struct plot_impl { };
251-
252- template <>
253- struct plot_impl <std::false_type>
254- {
255- template <typename IterableX, typename IterableY>
256- bool operator ()(const IterableX& x, const IterableY& y, const std::string& format)
257- {
258- // It's annoying that we have to repeat the code of plot() above
259- auto xs = std::distance (std::begin (x), std::end (x));
260- auto ys = std::distance (std::begin (y), std::end (y));
261- assert (xs == ys && " x and y data must have the same number of elements!" );
262-
263- PyObject* xlist = PyList_New (xs);
264- PyObject* ylist = PyList_New (ys);
265- PyObject* pystring = PyString_FromString (format.c_str ());
266-
267- auto itx = std::begin (x), ity = std::begin (y);
268- for (size_t i = 0 ; i < xs; ++i) {
269- PyList_SetItem (xlist, i, PyFloat_FromDouble (*itx++));
270- PyList_SetItem (ylist, i, PyFloat_FromDouble (*ity++));
271- }
272-
273- PyObject* plot_args = PyTuple_New (3 );
274- PyTuple_SetItem (plot_args, 0 , xlist);
275- PyTuple_SetItem (plot_args, 1 , ylist);
276- PyTuple_SetItem (plot_args, 2 , pystring);
277-
278- PyObject* res = PyObject_CallObject (detail::_pyplot_global::get ().s_python_function_plot , plot_args);
279-
280- Py_DECREF (xlist);
281- Py_DECREF (ylist);
282- Py_DECREF (plot_args);
283- if (res) Py_DECREF (res);
284-
285- return res;
286- }
287- };
288-
289- template <>
290- struct plot_impl <std::true_type>
291- {
292- template <typename Iterable, typename Callable>
293- bool operator ()(const Iterable& ticks, const Callable& f, const std::string& format)
294- {
295- // std::cout << "Callable impl called" << std::endl;
296-
297- if (begin (ticks) == end (ticks)) return true ;
298-
299- // We could use additional meta-programming to deduce the correct element type of y,
300- // but all values have to be convertible to double anyways
301- std::vector<double > y;
302- for (auto x : ticks) y.push_back (f (x));
303- return plot_impl<std::false_type>()(ticks,y,format);
304- }
305- };
306-
307- // recursion stop for the above
308- template <typename ... Args>
309- bool plot () { return true ; }
310-
311- template <typename A, typename B, typename ... Args>
312- bool plot (const A& a, const B& b, const std::string& format, Args... args)
313- {
314- return plot_impl<typename is_callable<B>::type>()(a,b,format) && plot (args...);
315- }
316-
317- #endif
318-
319- inline void legend () {
320- PyObject* res = PyObject_CallObject (detail::_pyplot_global::get ().s_python_function_legend , detail::_pyplot_global::get ().s_python_empty_tuple );
215+ inline void legend () {
216+ PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_legend , detail::_interpreter::get ().s_python_empty_tuple );
321217 if (!res) throw std::runtime_error (" Call to legend() failed." );
322218
323219 Py_DECREF (res);
@@ -333,7 +229,7 @@ namespace matplotlibcpp {
333229 PyObject* args = PyTuple_New (1 );
334230 PyTuple_SetItem (args, 0 , list);
335231
336- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_ylim , args);
232+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_ylim , args);
337233 if (!res) throw std::runtime_error (" Call to ylim() failed." );
338234
339235 Py_DECREF (list);
@@ -351,7 +247,7 @@ namespace matplotlibcpp {
351247 PyObject* args = PyTuple_New (1 );
352248 PyTuple_SetItem (args, 0 , list);
353249
354- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_xlim , args);
250+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_xlim , args);
355251 if (!res) throw std::runtime_error (" Call to xlim() failed." );
356252
357253 Py_DECREF (list);
@@ -360,11 +256,127 @@ namespace matplotlibcpp {
360256 }
361257
362258 inline void show () {
363- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_show , detail::_pyplot_global ::get ().s_python_empty_tuple );
259+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_show , detail::_interpreter ::get ().s_python_empty_tuple );
364260 if (!res) throw std::runtime_error (" Call to show() failed." );
365261
366262 Py_DECREF (res);
367263 }
368264
265+ #if __cplusplus > 199711L
266+ // C++11-exclusive content starts here, in particular the variadic plot()
267+
268+ namespace detail {
269+ template <typename T>
270+ using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
271+
272+ template <bool obj, typename T>
273+ struct is_callable_impl ;
274+
275+ template <typename T>
276+ struct is_callable_impl <false , T>
277+ {
278+ typedef is_function<T> type;
279+ }; // a non-object is callable iff it is a function
280+
281+ template <typename T>
282+ struct is_callable_impl <true , T>
283+ {
284+ struct Fallback { void operator ()(); };
285+ struct Derived : T, Fallback { };
286+
287+ template <typename U, U> struct Check ;
288+
289+ template <typename U>
290+ static std::true_type test ( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
291+
292+ template <typename U>
293+ static std::false_type test ( Check<void (Fallback::*)(), &U::operator()>* );
294+
295+ public:
296+ typedef decltype (test<Derived>(nullptr )) type;
297+ typedef decltype (&Fallback::operator ()) dtype;
298+ static constexpr bool value = type::value;
299+ }; // an object is callable iff it defines operator()
300+
301+ template <typename T>
302+ struct is_callable
303+ {
304+ // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
305+ typedef typename is_callable_impl<std::is_class<T>::value, T>::type type; // todo: restore remove_reference
306+ };
307+
308+ template <typename IsYDataCallable>
309+ struct plot_impl { };
310+
311+ template <>
312+ struct plot_impl <std::false_type>
313+ {
314+ template <typename IterableX, typename IterableY>
315+ bool operator ()(const IterableX& x, const IterableY& y, const std::string& format)
316+ {
317+ // It's annoying that we have to repeat the code of plot() above
318+ auto xs = std::distance (std::begin (x), std::end (x));
319+ auto ys = std::distance (std::begin (y), std::end (y));
320+ assert (xs == ys && " x and y data must have the same number of elements!" );
321+
322+ PyObject* xlist = PyList_New (xs);
323+ PyObject* ylist = PyList_New (ys);
324+ PyObject* pystring = PyString_FromString (format.c_str ());
325+
326+ auto itx = std::begin (x), ity = std::begin (y);
327+ for (size_t i = 0 ; i < xs; ++i) {
328+ PyList_SetItem (xlist, i, PyFloat_FromDouble (*itx++));
329+ PyList_SetItem (ylist, i, PyFloat_FromDouble (*ity++));
330+ }
331+
332+ PyObject* plot_args = PyTuple_New (3 );
333+ PyTuple_SetItem (plot_args, 0 , xlist);
334+ PyTuple_SetItem (plot_args, 1 , ylist);
335+ PyTuple_SetItem (plot_args, 2 , pystring);
336+
337+ PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_plot , plot_args);
338+
339+ Py_DECREF (xlist);
340+ Py_DECREF (ylist);
341+ Py_DECREF (plot_args);
342+ if (res) Py_DECREF (res);
343+
344+ return res;
345+ }
346+ };
347+
348+ template <>
349+ struct plot_impl <std::true_type>
350+ {
351+ template <typename Iterable, typename Callable>
352+ bool operator ()(const Iterable& ticks, const Callable& f, const std::string& format)
353+ {
354+ // std::cout << "Callable impl called" << std::endl;
355+
356+ if (begin (ticks) == end (ticks)) return true ;
357+
358+ // We could use additional meta-programming to deduce the correct element type of y,
359+ // but all values have to be convertible to double anyways
360+ std::vector<double > y;
361+ for (auto x : ticks) y.push_back (f (x));
362+ return plot_impl<std::false_type>()(ticks,y,format);
363+ }
364+ };
365+ }
366+
367+ // recursion stop for the above
368+ template <typename ... Args>
369+ bool plot () { return true ; }
370+
371+ template <typename A, typename B, typename ... Args>
372+ bool plot (const A& a, const B& b, const std::string& format, Args... args)
373+ {
374+ return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot (args...);
375+ }
376+
377+ #endif
378+
379+
380+
369381
370382}
0 commit comments